手把手教你玩轉ESP8266(原理+驅動)

在嵌入式開發中,無線通信的方式有很多,其中 WIFI 是繞不開的話題。說到 WIFI 通信,就不得不提 ESP8266了。

ESP8266 是一款高性能的 WIFI 串口模塊,實現透明傳輸。只要有一定的串口知識,不需要知道 WIFI 原理就可以上手,在業內應用廣泛。

1. 源碼下載

本文首發 良許嵌入式網 :https://www.lxlinux.net/e/ ,歡迎關注!

本文所涉及的源碼及安裝包如下(由于平臺限制,請點擊以下鏈接閱讀原文下載):

https://www.lxlinux.net/e/stm32/esp8266-tutorial.html

  • STM32F103C8T6模板工程

  • 本文的源碼

  • 串口調試助手

  • 網絡調試助手

  • CH340驅動

如果不知道如何搭建 STM32 編程環境,不知道如何燒錄 STM32 代碼,可以閱讀這篇文章:

https://www.lxlinux.net/e/stm32/stm32-quick-start-for-beginner.html

如果你連代碼都不知道怎么燒錄到 STM32 的,可以參考下文,提供了 5 種代碼燒錄方式:

https://www.lxlinux.net/e/stm32/five-ways-to-flash-program-to-stm32.html

文中所使用的芯片是 STM32F103C8T6 ,配套了一個工程模板,如果你需要自己搭建一個工程模板,可以參考下文:

https://www.lxlinux.net/e/stm32/create-stm32-hal-project-template.html

2. ESP8266介紹

ESP8266 是一個非常強大的 WIFI 模塊,可以利用串口與單片機進行通訊,從而編程實現控制 ESP8266。利用 ESP8266 可以訪問一些 API,獲取天氣信息或者完成網絡授時,也可以連接云平臺進行開發。不過因為是串口傳輸,速度較慢,不能用來傳輸圖像、視頻這些大容量的數據,但是傳些傳感器數據還是綽綽有余的。

我們常說的 ESP8266 是指 ESP8266 WIFI 模塊,它是物聯網和嵌入式開發常用的模塊,其中 ESP8266 是 WIFI 模塊的芯片型號。

ESP8266 有 ESP-01/01S/07/07S/12E/12F/12S 等規格,還有正點原子自研的 ATK-ESP8266 (修改了固件及模組引腳)。

本文用到的是 ESP-01S,長下面這樣。這種模組非常便宜,某寶幾塊錢一個,建議可以買幾個囤著。

3. 三種調試方式

ESP8266 已經是一款很成熟的模組了,前文提到,它可以通過串口進行通訊。

既然可以進行串口通訊,那么我們就可以使用以下三種方法進行調試。

  • USB 轉 TTL 工具

這玩意兒大家應該非常熟悉了,通常我們用它來打印單片機 log。

當然,配合上位機(比如串口調試助手),我們也可以使用它對一些模組進行調試,比如:ESP8266、4G模組、藍牙,等等。

如果對這個工具使用不熟悉的小伙伴,可以閱讀下文:

【零基礎快速上手STM32開發(手把手保姆級教程)】

USB轉TTL模塊ESP8266
3.3V3.3V
TXDRX
RXDTX
GNDGND

使用 USB 轉 TTL 工具調試 ESP8266,可以通過上面的表格進行接線。

3.3V 相接后可能無法啟動 ESP8266,這是因為 USB 轉 TTL 模組的 3.3V 并沒有真的達到 3.3V,莫慌,直接將 ESP8266 的3.3V 引腳接入 USB 轉 TTL 的 5V 引腳,如果 ESP8266 會發燙到無法觸摸就拔掉,如果溫度你手指還能接受,那就沒問題,ESP8266 還是沒那么脆弱的。

接好線之后,將 USB 端連接到電腦,打開串口調試助手就可以進行調試了。

  • USB 轉 ESP8266WIFI 模塊

上面的 USB 轉 TTL 模組需要你動手去接線,比較麻煩,而且要是線有一根接錯了,就無法正常調試了。

而這個模組專門是為了調試 ESP8266 而設計,不需要一個個引腳接線,直接把 ESP8266 往上一插就可以啦,超方便的。同樣,USB 端連接電腦,打開串口調試助手就可以進行調試了。

  • 單片機調試

這種就是在項目中最常用的方式了。需要將 ESP8266 接到單片機的任意一個串口,然后再編寫代碼驅動 ESP8266 ,實現各種業務邏輯。

本文就是手把手教大家編寫一個 ESP8266 驅動程序。

上電:正常工作驗證

模塊拿到手之后,我們需要先確保這個模組是正常的,否則后面的調試、寫代碼都是白搭。

首先,上電后,藍色燈微弱閃爍后熄滅,表示正常工作。

還可以更進一步,接好線之后,然后打開串口調試助手發送 AT(并且還要敲一個回車),ESP8266 回復 OK,就是正常啟動了。

4. ESP8266工作模式

ESP8266 支持 STA、AP、AP+STA 三種工作模式。

  • STA 模式(Station)

一般用于遠距離傳輸。ESP8266 通過路由器連接互聯網,終端設備通過互聯網實現對設備的遠程控制。簡單來說,此時的 ESP8266 可以當作是一個客戶端,可以向服務端進行數據的下載與傳輸。這就類似于,手機/平板/筆記本(客戶端)可以通過 WIFI 連接到路由器進行上網。

  • AP 模式(Access Point)

一般用于近距離傳輸。ESP8266 作為熱點,提供無線接入服務、數據訪問,一般的無線路由/網橋工作在 AP 模式下,最多支持 4 臺設備接入。簡單來說,此時的 ESP8266 可以當作是一個服務端。這就類似于,ESP8266 變身為一個路由器,然后手機/平板/筆記本可以通過 WIFI 連接到 ESP8266 進行上網。

  • AP+STA 模式

兩種模式的共存模式,可以通過互聯網控制可實現無縫切換,方便操作。簡單來說,此時的 ESP8266 可以當作是一個路由器既可以做服務端接收也可以當客戶端連接路由器,進行聯網傳輸和控制。

5. AT指令介紹

5.1 什么是AT指令?

AT 指令(AT Commands)最早是由發明撥號調制解調器的賀氏公司為了控制撥號調制解調器而發明的控制協議。后來隨著網絡帶寬的升級,速度很低的撥號調制解調器基本退出市場,但是 AT 指令被保留了下來。

在嵌入式開發中,經常是使用 AT 命令去控制各種通訊模塊,比如 ESP8266 模塊、4G 模塊、GPRS 模塊等等。一般就是主芯片通過硬件接口(比如串口、SPI)發送 AT 指令給通訊模塊,模塊接收到數據之后回應響應的數據。

5.2 常用AT指令介紹

AT 指令分為四種類型:

類型格式功能
測試指令AT + < X > = ?查詢設置命令或內部程序設置的參數及其取值范圍
查詢指令AT + < X > ?返回參數的當前值
設置指令AT + < X > = < ... >設置用戶自定義的參數值
執行指令AT + < X >執行受模塊內部程序控制的變參數不可變

AT 指令有近百條,但常用的就十幾條,理解起來也非常簡單,現在舉例一些常用指令,并使用這些指令一步一步的通過 TCP 連接到遠程的服務器實現收發數據。

AT指令功能
AT測試是否正常啟動
AT+CWMODE=1設置 STA 模式
AT+CWMODE=2設置 AP 模式
AT+CWMODE=3設置 AP+STA 模式
AT+RST重啟生效
AT+CWSAP=”SSID”,”password”,1,4設置 AP 參數:賬號為SSID ,密碼為password,通道號為 1,加密方式為:WPA_WPA2_PSK
AT+CIPMUX=0開啟單連接
AT+CIPMUX=1開啟多連接
AT+CIPSERVER=1,8080開啟 SERVER 模式,設置端口為 8080
AT+CIPSTART=“TCP”,"192.168.X.XXX”,8080建立 TCP 連接到”192.168.X.XXX”,8080
AT+CIPSTART=“UDP”,“192.168.X.XXX”,8080建立 UDP 連接到”192.168.X.XXX”,8080
AT+CIPCLOSE斷開 TCP 連接
AT+CWQAP斷開熱點
AT+CIPSEND=n開始傳輸,n表示需要傳輸的字節數
AT+CIPSEND=0,n向 ID0 發送 n 字節數據包,n的值自己定
AT+CIPMODE=1開啟透傳模式
AT+CIPSEND開始發送數據
AT+CIPMODE=0退出透傳
AT+CWJAP="SSID,“password”加入 WIFI 熱點:SSID ,密碼為:password
AT+CIFSR查詢 ESP8266 的 IP 地址
AT+CIPSTA?查詢 ESP8266 的 IP 、網關地址和子網掩碼

接下來我們要用串口助手發送 AT 指令,如果你還不會用串口助手,那么動動小手跟我操作:

  1. 插上 USB,選擇正確的串口號,正確的串口號是插上 USB 后多出的串口號;
  2. 選擇波特率,ESP8266 默認波特率是 115200 ,可以通過 AT 指令修改;
  3. 點擊「打開」或者「打開串口」;
  4. 在輸入框輸入指令,AT 指令要以回車結尾;
  5. 點擊「發送」,觀察 ESP8266 的返回值;
  6. 使用完點「斷開」或者「關閉串口」。

不一定要用我的串口助手,別的串口助手也可以(比如正點原子開發的串口助手,甚至你自己寫一個也行),都是一樣的。

如果已經插上 USB,選擇了正確的串口號,但是出現串口打不開并輸出「【ERROR】Cannot set COM port parameters」 的情況,可能是 CH340 驅動還沒安裝,或者需要卸載重新安裝一下。教你解決:

  1. 先點「斷開」,斷開串口;
  2. 打開 CH340 驅動安裝程序,我文章開頭有提供;
  3. 如果你沒有安裝過,點擊「安裝」;如果你安裝過,點擊「卸載」再點擊「安裝」;
  4. 安裝好后拔插一下 USB,看看串口號有沒有變,有變更換一下串口號;
  5. 最后點「打開」或者「打開串口」就可以啦。

如果還不明白的,可以參考下文,有圖文教程:

【零基礎快速上手STM32開發(手把手保姆級教程)】

5.2.1 測試模塊是否正常(AT)

發送 AT,ESP8266 回復 OK,就是正常啟動了。

5.2.2 開啟/關閉回顯(ATE1/ATE0)

發送了指令 AT,模塊回復了「AT OK」,即模塊將發送過來的指令原封不動的先復述了一遍后接著發送有效回復,我們稱這種復述為 回顯

發送 ATE0,關閉回顯

發送 ATE1,開啟回顯

5.2.3 設置AP模式及AP參數(AT+CWMODE,AT+CWSAP)

發送 AT+CWMODE?,查詢模塊當前處于哪一種模式;

發送 AT+CWMODE=1,設置 STA 模式;

發送 AT+CWMODE=2,設置 AP 模式;

發送 AT+CWMODE=3,設置 AP+STA 模式。

如果當前為 AP 模式,那么發送 AT+CWSAP="SSID","password",通道,加密方式 ,可以設置熱點。這個過程相當于給路由器設置熱點名稱及密碼,方便手機連接。

例如:發送 AT+CWSAP="ESP8266-liangxu","12345678",5,3 ,則可以將熱點名設置為 ESP8266-liangxu ,密碼為 12345678,使用通道 5 ,加密方式為 WPA2_PSK(1-WEP,2-WPA_PSK,3-WPA2_PSK,4-WPA_WPA2_PSK),這里的通道對應的就是不同的射頻頻率,如果同一空間內存在相同通道的 WIFI 信號,將會產生干擾,影響上網質量,因此可以設置通道來避免這種干擾,常用的通道有 1、6、11,因為這三個通道互不產生干擾。

5.2.4 設置為STA模式(AT+CWMODE=1,AT+CWJAP,AT+CIFSR)

發送 AT+CWMODE=1,設置 STA 模式;

發送 AT+CWJAP="SSID","password",連接路由器;

發送 AT+CIPSTA?,路由器分配給 ESP8266 的局域網 IP 以及網關地址和子網掩碼;

發送 AT+CIFSR,查詢 ESP8266 的 IP 地址信息。

5.2.5 TCP透傳
5.2.5.1 準備工作

實現 TCP 透傳需要搭建一個 TCP 服務器,這里我們就使用網絡調試助手 + 自己的電腦就好。我的網絡調試助手是正點原子的,大家不一定要用我的,只要是網絡助手都可以。

首先我們需要知道自己電腦的 IP 地址,有兩種方式:

方法1:打開電腦的設置:

方法2:使用命令提示符:

打開網絡調試助手,跟我配置,超快的。端口號 TCP 協議一般填8080。

5.2.5.2 正式開始

接下來我們利用串口助手將 ESP8266 連接到 TCP 服務器。

發送 AT+CIPSTART="協議模式","服務端IP地址",端口號 ,建立連接,協議模式有 TCP 和 UDP ;

因為我們剛剛搭建的是 TCP 服務器,服務器 IP 地址是 192.168.1.27,所以我們發送 AT+CIPSTART="TCP","192.168.1.27",8080 。如果不出意外,過一會兒 ESP8266 就連接上 TCP 服務器了,將返回 CONNECT OK 。

但這個時候,我們再在輸入框發送內容的話,依然是默認為指令。如果我們想把數據直接發送給 TCP 服務器,那么就需要開啟透傳模式。

所謂的透傳模式,可以視為 ESP8266 為透明狀態,客戶端發送的信息直接就傳輸給服務端。

我們需要先發送 AT+CIPMODE=1,開啟透傳模式。然后,再發送 AT+CIPSEND,才真正開始透傳發送。

此時,你發送的任何數據,就直接傳輸到服務器了。

退出透傳:先發送 +++(不要帶回車),再發送 AT+CIPMODE=0

如果不退出透傳,發出來的就算是 AT 指令,它也會被認為是普通字符串,直接透傳給對方。

AT+CWCLOSE,斷開 TCP 連接。

AT+CWQAP,斷開熱點。

6. 編程實戰

6.1 硬件接線

本教程使用的硬件如下:

  • 單片機:STM32F103C8T6

  • WiFi模塊:ESP-01S

  • 串口:USB 轉 TTL

  • 燒錄器:ST-LINK V2。

接線可參照下表:

ESP8266STM32USB 轉 TTL
3V33.3
TXA3
RXA2
GNDG
A10TX
A9RX
GGND

燒錄的時候接線如下表,如果不會燒錄的話可以看我之前的文章【STM32下載程序的五種方法】。

ST-Link V2STM32
SWCLKSWCLK
SWDIOSWDIO
GNDGND
3.3V3V3

其中 USB 轉 TTL 連接的是 STM32 的串口1(A9和A10),用來打印 STM32 的輸出;STM32 的串口2(A2和A3),用來控制 ESP8266。

接好就像這樣:

6.2 模板工程加載ESP8266模塊代碼

打開模板工程和 ESP8266 驅動源碼。

復制好后打開工程。

跟著我的貪吃蛇點點點:)

6.3 串口通訊實現

實現向串口發送數據,并等待返回值。ESP8266 的 TX 和 RX 定義在串口2。

  1. 定義串口句柄 g_uart_handle ,并調用 HAL_UART_Init 進行初始化。
UART_HandleTypeDef g_uart_handle;void esp8266_uart_init(uint32_t baudrate)
{g_uart_handle.Instance          = ESP8266_UART_INTERFACE;       /* ESP8266 UART */g_uart_handle.Init.BaudRate     = baudrate;                     /* 波特率 */g_uart_handle.Init.WordLength   = UART_WORDLENGTH_8B;           /* 數據位 */g_uart_handle.Init.StopBits     = UART_STOPBITS_1;              /* 停止位 */g_uart_handle.Init.Parity       = UART_PARITY_NONE;             /* 校驗位 */g_uart_handle.Init.Mode         = UART_MODE_TX_RX;              /* 收發模式 */g_uart_handle.Init.HwFlowCtl    = UART_HWCONTROL_NONE;          /* 無硬件流控 */g_uart_handle.Init.OverSampling = UART_OVERSAMPLING_16;         /* 過采樣 */HAL_UART_Init(&g_uart_handle);                                  /* 使能ESP8266 UART */
}

其中,ESP8266_UART_INTERFACE 是宏定義,指代的就是 USART2

傳入參數 baudrate 可以定義該串口的波特率。

  1. 初始化串口底層函數,調用 HAL_UART_MspInit 函數。

注意最后一行,需要調用 __HAL_UART_ENABLE_IT 函數使能接收中斷。

void HAL_UART_MspInit(UART_HandleTypeDef *huart)
{GPIO_InitTypeDef gpio_init_struct;if (huart->Instance == USART_UX)                            /* 如果是串口1,進行串口1 MSP初始化 */{....// 省略串口1相關代碼....}else if (huart->Instance == ESP8266_UART_INTERFACE)                 /* 如果是ESP8266 UART */{ESP8266_UART_TX_GPIO_CLK_ENABLE();                              /* 使能UART TX引腳時鐘 */ESP8266_UART_RX_GPIO_CLK_ENABLE();                              /* 使能UART RX引腳時鐘 */ESP8266_UART_CLK_ENABLE();                                      /* 使能UART時鐘 */gpio_init_struct.Pin    = ESP8266_UART_TX_GPIO_PIN;             /* UART TX引腳 */gpio_init_struct.Mode   = GPIO_MODE_AF_PP;                          /* 復用推挽輸出 */gpio_init_struct.Pull   = GPIO_NOPULL;                              /* 無上下拉 */gpio_init_struct.Speed  = GPIO_SPEED_FREQ_HIGH;                     /* 高速 */HAL_GPIO_Init(ESP8266_UART_TX_GPIO_PORT, &gpio_init_struct);    /* 初始化UART TX引腳 */gpio_init_struct.Pin    = ESP8266_UART_RX_GPIO_PIN;             /* UART RX引腳 */gpio_init_struct.Mode   = GPIO_MODE_INPUT;                          /* 輸入 */gpio_init_struct.Pull   = GPIO_NOPULL;                              /* 無上下拉 */gpio_init_struct.Speed  = GPIO_SPEED_FREQ_HIGH;                     /* 高速 */HAL_GPIO_Init(ESP8266_UART_RX_GPIO_PORT, &gpio_init_struct);    /* 初始化UART RX引腳 */HAL_NVIC_SetPriority(ESP8266_UART_IRQn, 0, 0);                  /* 搶占優先級0,子優先級0 */HAL_NVIC_EnableIRQ(ESP8266_UART_IRQn);                          /* 使能UART中斷通道 */__HAL_UART_ENABLE_IT(huart, UART_IT_RXNE);                          /* 使能UART接收中斷 */}
}
  1. 使用接收中斷+超時判斷,完成數據接收。

由于 ESP8266 通過串口返回的數據長度不固定,所以我們可以使用接收中斷+超時判斷的方法完成數據接收。具體方法可以參考下文:

【STM32串口接收不定長數據(接收中斷+超時判斷)】

在串口中斷服務函數里,我們可以將接收到的字符保存在接收緩沖區里 g_uart_rx_buf ,并定義一個變量 esp8266_cnt 計算總共收到了多少個字符。

void ESP8266_UART_IRQHandler(void)
{uint8_t receive_data = 0;   if(__HAL_UART_GET_FLAG(&g_uart_handle, UART_FLAG_RXNE) != RESET){if(esp8266_cnt >= sizeof(g_uart_rx_buf))esp8266_cnt = 0; //防止串口被刷爆HAL_UART_Receive(&g_uart_handle, &receive_data, 1, 1000);//串口2接收1位數據g_uart_rx_buf[esp8266_cnt++] = receive_data;  }HAL_UART_IRQHandler(&g_uart_handle);
}

假如一幀的數據接收完成了,那么 esp8266_cnt 變量的值應該維持不變。

我們通過 while 死循環不停計算當前收到多少個字符,當前統計的值計算在 esp8266_cnt 變量里,定義另一個變量 esp8266_cntPre ,用于記錄上一次統計接收到的數據的長度,如果本次統計數據長度跟上一次一樣的話就說明數據接收完成了。代碼如下:

uint8_t esp8266_wait_receive(void)
{if(esp8266_cnt == 0)                             //如果接收計數為0 則說明沒有處于接收數據中,所以直接跳出,結束函數return ESP8266_ERROR;if(esp8266_cnt == esp8266_cntPre) {                //如果上一次的值和這次相同,則說明接收完畢esp8266_cnt = 0;                            //清0接收計數return ESP8266_EOK;                            //返回接收完成標志}esp8266_cntPre = esp8266_cnt;                    //置為相同return ESP8266_ERROR;                            //返回接收未完成標志
}

當然,接收到的數據使用完成之后,我們就應該清空接收緩沖區,并將計數器置 0 ,方便下一次接收。

void esp8266_clear(void)
{memset(g_uart_rx_buf, 0, sizeof(g_uart_rx_buf));esp8266_cnt = 0;
}

接下來,就是最關鍵的一個函數了。我們使用這個函數通過串口向 ESP8266 發送一個字符串,并循環等待我們所期待得到的字符串。

在下面這個函數里,cmd 變量是我們向 ESP8266 發送的字符串,res 變量是我們期待得到的回復。

比如,我們向 ESP8266 發送 AT 這個字符串,那么 ESP8266 如果正常的話應該會回復 OK 。此時,cmd 就是 AT ,而 res 就是 OK

uint8_t esp8266_send_command(char *cmd, char *res)
{uint8_t timeOut = 250;esp8266_clear();HAL_UART_Transmit(&g_uart_handle, (unsigned char *)cmd, strlen((const char *)cmd), 100);while(timeOut--) {if(esp8266_wait_receive() == ESP8266_EOK) {                        //如果收到數據if(strstr((const char *)g_uart_rx_buf, res) != NULL)        //如果檢索到關鍵詞return ESP8266_EOK;}delay_ms(10);}return ESP8266_ERROR;
}

6.4 編程實現AT指令交互

接下來,我們就可以使用 esp8266_send_command 發送 AT 指令并確定 ESP8266 回復是否正確。以代碼方式實現各個 AT 指令,例子如下:

uint8_t esp8266_at_test(void)
{return esp8266_send_command("AT\r\n", "OK");
}uint8_t esp8266_sw_reset(void)
{return esp8266_send_command("AT+RST\r\n", "OK");
}uint8_t esp8266_set_mode(uint8_t mode)
{switch (mode) {case ESP8266_STA_MODE:return esp8266_send_command("AT+CWMODE=1\r\n", "OK");    /* Station模式 */case ESP8266_AP_MODE:return esp8266_send_command("AT+CWMODE=2\r\n", "OK");    /* AP模式 */case ESP8266_STA_AP_MODE:return esp8266_send_command("AT+CWMODE=3\r\n", "OK");    /* AP+Station模式 */default:return ESP8266_EINVAL;}
}

由于 AT 指令有很多,這里只截取了其中的一部分,完整的可以參考我提供的代碼。

6.5 編程實現STA模式

STA 模式實現思路如下:

  1. 進入 STA 模式(要重啟生效);
  2. 設置單路連接;
  3. 連接 WIFI(注意 ESP8266 和服務端要在同一網絡內);
  4. 淺查一下 ESP8266 的 IP 地址,不查也可以;
  5. 連接TCP服務器;
  6. 開啟透傳。
uint8_t esp8266_single_connection(void)
{return esp8266_send_command("AT+CIPMUX=0\r\n", "OK");
}uint8_t esp8266_join_ap(char *ssid, char *pwd)
{char cmd[64];sprintf(cmd, "AT+CWJAP=\"%s\",\"%s\"\r\n", ssid, pwd);return esp8266_send_command(cmd, "WIFI GOT IP");
}uint8_t esp8266_get_ip(char *buf)
{char *p_start;char *p_end;if (esp8266_send_command("AT+CIFSR\r\n", "STAIP") != ESP8266_EOK)return ESP8266_ERROR;p_start = strstr((const char *)g_uart_rx_buf, "\"");p_end = strstr(p_start + 1, "\"");*p_end = '\0';sprintf(buf, "%s", p_start + 1);return ESP8266_EOK;
}uint8_t esp8266_connect_tcp_server(char *server_ip, char *server_port)
{char cmd[64];sprintf(cmd, "AT+CIPSTART=\"TCP\",\"%s\",%s\r\n", server_ip, server_port);return esp8266_send_command(cmd, "CONNECT");
}uint8_t esp8266_enter_unvarnished(void)
{uint8_t ret;ret  = esp8266_send_command("AT+CIPMODE=1\r\n", "OK");ret += esp8266_send_command("AT+CIPSEND\r\n", ">");if (ret == ESP8266_EOK)return ESP8266_EOK;elsereturn ESP8266_ERROR;
}/*** @brief       ESP8266初始化* @param       baudrate: ESP8266 UART通訊波特率* @retval      ESP8266_EOK  : ESP8266初始化成功,函數執行成功*              ESP8266_ERROR: ESP8266初始化失敗,函數執行失敗*/
uint8_t esp8266_init(uint32_t baudrate)
{char ip_buf[16];esp8266_uart_init(baudrate);                /* ESP8266 UART初始化 *//* 讓WIFI退出透傳模式 */while(esp8266_exit_unvarnished())delay_ms(500);printf("1.AT\r\n");while(esp8266_at_test())delay_ms(500);printf("2.RST\r\n");while(esp8266_sw_reset())delay_ms(500);while(esp8266_disconnect_tcp_server())delay_ms(500);printf("3.CWMODE\r\n");while(esp8266_set_mode(ESP8266_STA_MODE))delay_ms(500);printf("4.AT+CIPMUX\r\n");  //設置單路連接模式,透傳只能使用此模式while(esp8266_multi_connection())delay_ms(500);printf("5.CWJAP\r\n");      //連接WIFIprintf("%s\r\n",WIFI_SSID); while(esp8266_join_ap(WIFI_SSID, WIFI_PWD))delay_ms(1000);printf("6.CIFSR\r\n");while(esp8266_get_ip(ip_buf))delay_ms(500);printf("ESP8266 IP: %s\r\n", ip_buf);printf("7.CIPSTART\r\n");while(esp8266_connect_tcp_server(TCP_SERVER_IP, TCP_SERVER_PORT))delay_ms(500);printf("8.CIPMODE\r\n");while(esp8266_enter_unvarnished())delay_ms(500);printf("ESP8266初始化完成\r\n");return ESP8266_EOK;
}

代碼完成,編譯,燒錄,打開串口,串口輸出,實現效果當當當:

6.6 編程實現AP模式

AP 模式實現思路很簡單:

  1. 進入 AP 模式(要重啟生效);
  2. 設置 AP 參數;
  3. 開啟多連接或單連接。
uint8_t esp8266_set_ap(char *ssid, char *pwd)
{char cmd[64];sprintf(cmd, "AT+CWSAP=\"%s\",\"%s\",5,3\r\n", ssid, pwd);return esp8266_send_command(cmd, "OK");
}uint8_t esp8266_multi_connection(void)
{return esp8266_send_command("AT+CIPMUX=1\r\n", "OK");
}uint8_t esp8266_init(uint32_t baudrate)
{char ip_buf[16];esp8266_uart_init(baudrate);                /* ESP8266 UART初始化 *//* 讓WIFI退出透傳模式 */while(esp8266_exit_unvarnished())delay_ms(500);printf("1.AT\r\n");while(esp8266_at_test())delay_ms(500);printf("2.RST\r\n");while(esp8266_sw_reset())delay_ms(500);while(esp8266_disconnect_tcp_server())delay_ms(500);printf("3.CWMODE\r\n");while(esp8266_set_mode(ESP8266_AP_MODE))delay_ms(500);printf("4.CWSAP\r\n");      //設置APprintf("%s\r\n",WIFI_SSID); while(esp8266_set_ap(WIFI_SSID, WIFI_PWD))delay_ms(1000);printf("5.AT+CIPMUX\r\n");  //設置多路連接模式while(esp8266_multi_connection())delay_ms(500);printf("ESP8266_Init OK\r\n");return ESP8266_EOK;
}

代碼完成,燒錄,打開串口,串口輸出,實現效果當當當:

6.7 編程實現AP+STA模式

AP+STA 模式使用不多,就是前兩個的結合,這里就不多介紹了。仿照 STA 模式和 AP 模式寫相應的 AT 指令代碼就好啦,思路如下,需要注意的是要啟動多連接:

  1. 設置為 AP+STA 模式(要重啟生效);
  2. AT+CWJAP=”SSID”,”password”,連接WIFI(注意 ESP8266 和服務端要在同一網絡內);
  3. AT+CWSAP="SSID","password",通道,加密方式,設置AP熱點;
  4. AT+CIPMUX=1,啟動多連接;
  5. AT+CIPSERVER=1,8080,打開服務器端口為8080。
uint8_t esp8266_join_ap(char *ssid, char *pwd)
{char cmd[64];sprintf(cmd, "AT+CWJAP=\"%s\",\"%s\"\r\n", ssid, pwd);return esp8266_send_command(cmd, "WIFI GOT IP");
}uint8_t esp8266_set_ap(char *ssid, char *pwd)
{char cmd[64];sprintf(cmd, "AT+CWSAP=\"%s\",\"%s\",5,3\r\n", ssid, pwd);return esp8266_send_command(cmd, "OK");
}uint8_t esp8266_multi_connection(void)
{return esp8266_send_command("AT+CIPMUX=1\r\n", "OK");
}uint8_t esp8266_open_server()
{return esp8266_send_command("AT+CIPSERVER=1,8080\r\n", "OK");
}uint8_t esp8266_init(uint32_t baudrate)
{char ip_buf[16];esp8266_uart_init(baudrate);                /* ESP8266 UART初始化 *//* 讓WIFI退出透傳模式 */while(esp8266_exit_unvarnished())delay_ms(500);/* STA+AP模式 */printf("1.AT\r\n");while(esp8266_at_test())delay_ms(500);printf("2.RST\r\n");while(esp8266_sw_reset())delay_ms(500);while(esp8266_disconnect_tcp_server())delay_ms(500);printf("3.CWMODE\r\n");while(esp8266_set_mode(ESP8266_STA_AP_MODE))delay_ms(500);printf("4.CWJAP\r\n");      //連接WIFIprintf("%s\r\n",WIFI_SSID); while(esp8266_join_ap(WIFI_SSID, WIFI_PWD))delay_ms(1000);printf("5.CWSAP\r\n");      //設置APwhile(esp8266_set_ap("ESP8266-liangxu", "12345678"))delay_ms(1000);printf("6.AT+CIPMUX\r\n");  //設置多路連接模式while(esp8266_multi_connection())delay_ms(500);printf("7.CIPSERVER\r\n");  //打開服務器端口8080while(esp8266_open_server())delay_ms(500);printf("ESP8266_Init OK\r\n");return ESP8266_EOK;
}

代碼完成,編譯,燒錄,打開串口,串口輸出,實現效果當當當:

esp8266.h文件內容如下:

#ifndef __ESP8266_H__
#define __ESP8266_H__#include <stdint.h>
#include "usart.h"extern UART_HandleTypeDef g_uart_handle;/* 引腳定義 */
#define ESP8266_UART_TX_GPIO_PORT           GPIOA
#define ESP8266_UART_TX_GPIO_PIN            GPIO_PIN_2
#define ESP8266_UART_TX_GPIO_CLK_ENABLE()   do{ __HAL_RCC_GPIOA_CLK_ENABLE(); }while(0) /* PC口時鐘使能 */#define ESP8266_UART_RX_GPIO_PORT           GPIOA
#define ESP8266_UART_RX_GPIO_PIN            GPIO_PIN_3
#define ESP8266_UART_RX_GPIO_CLK_ENABLE()   do{ __HAL_RCC_GPIOA_CLK_ENABLE(); }while(0) /* PD口時鐘使能 */#define ESP8266_UART_INTERFACE              USART2
#define ESP8266_UART_IRQn                   USART2_IRQn
#define ESP8266_UART_IRQHandler             USART2_IRQHandler
#define ESP8266_UART_CLK_ENABLE()           do{ __HAL_RCC_USART2_CLK_ENABLE(); }while(0) /* UART2時鐘使能 *//* UART收發緩沖大小 */
#define ESP8266_UART_RX_BUF_SIZE            128
#define ESP8266_UART_TX_BUF_SIZE            64/* 錯誤代碼 */
#define ESP8266_EOK                         0   /* 沒有錯誤 */
#define ESP8266_ERROR                       1   /* 通用錯誤 */
#define ESP8266_ETIMEOUT                    2   /* 超時錯誤 */
#define ESP8266_EINVAL                      3   /* 參數錯誤 *//* 工作模式 */
#define ESP8266_STA_MODE                    1
#define ESP8266_AP_MODE                     2
#define ESP8266_STA_AP_MODE                 3#define WIFI_SSID                           "HuaweiAP-1ED0"
#define WIFI_PWD                            "87654321"#define TCP_SERVER_IP                       "192.168.1.27"
#define TCP_SERVER_PORT                     "8080"uint8_t esp8266_init(uint32_t baudrate);
void esp8266_clear(void);
void esp8266_uart_printf(char *fmt, ...);
#endif

7. 小結

通過學習和實踐,希望大家能夠了解并掌握 ESP8266 的特性和使用,從而更好地應用于嵌入式開發。無論是構建智能家居系統還是開發物聯網設備,ESP8266 都可以成為您的得力助手,讓我們一起玩轉 ESP8266,love and peace!


另外,想進大廠的同學,一定要好好學算法,這是面試必備的。這里準備了一份 BAT 大佬總結的 LeetCode 刷題寶典,很多人靠它們進了大廠。

刷題 | LeetCode算法刷題神器,看完 BAT 隨你挑!

有收獲?希望老鐵們來個三連擊,給更多的人看到這篇文章

推薦閱讀:

  • 程序員必備編程資料大全
  • 程序員必備軟件資源

歡迎關注我的博客:良許嵌入式教程網,滿滿都是干貨!

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/news/214735.shtml
繁體地址,請注明出處:http://hk.pswp.cn/news/214735.shtml
英文地址,請注明出處:http://en.pswp.cn/news/214735.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

作為一個產品經理帶你了解Axure的安裝和基本使用

1.Axure的簡介 Axure是一種強大的原型設計工具&#xff0c;它允許用戶創建交互式的、高保真度的原型&#xff0c;以及進行用戶體驗設計和界面設計。Axure可以幫助設計師和產品經理快速創建和共享原型&#xff0c;以便團隊成員之間進行溝通和反饋。Axure提供了豐富的交互組件和功…

Spring--10--Spring Bean的生命周期

提示&#xff1a;文章寫完后&#xff0c;目錄可以自動生成&#xff0c;如何生成可參考右邊的幫助文檔 文章目錄 1.Spring Bean1.1 什么是 Bean簡而言之&#xff0c;bean 是由 Spring IoC 容器實例化、組裝和管理的對象。 1.2 Spring框架管理Bean對象的優勢 2.Bean的生命周期實例…

西工大網絡空間安全學院計算機系統基礎實驗二(phase_2下——漫漫深夜過后的黎明!!!)

內存地址內存地址中的數注釋指向這塊內存的寄存器0xffffd0e8函數phase_2的棧幀0xffffd0e40xffffd0f4函數phase_2的棧幀0xffffd0e00x5655b7b0函數phase_2的棧幀0xffffd0dc0x565566ca函數read_six_numbers的返回地址&#xff0c;函數phase_2的棧幀0xffffd0d80x5655af64舊%ebx的值…

SpringIOC之ConditionEvaluator

博主介紹:?全網粉絲5W+,全棧開發工程師,從事多年軟件開發,在大廠呆過。持有軟件中級、六級等證書。可提供微服務項目搭建與畢業項目實戰,博主也曾寫過優秀論文,查重率極低,在這方面有豐富的經驗? 博主作品:《Java項目案例》主要基于SpringBoot+MyBatis/MyBatis-plus+…

Netty性能好的原因是什么

Netty性能好的原因 廢話篇Netty性能好的原因是什么1. 非阻塞IO模型高效的Reactor線程模型零拷貝內存池設計無鎖串行化設計高性能序列化協議 廢話篇 相信有同學會經常被問到這樣的問題&#xff0c;不妨下次被面試官問到這種問題&#xff0c;我們可以這樣回答&#xff01; Nett…

簡單實用的firewalld命令

簡單實用的firewalld命令 一、查看防火墻是否打開二、查詢、開放、關閉端口三、查看已監聽端口四、驗證 一、查看防火墻是否打開 systemctl status firewalld ● firewalld.service - firewalld - dynamic firewall daemonLoaded: loaded (/usr/lib/systemd/system/firewalld.…

map.getOrDefault

map.getOrDefault 是 Java 中的一個方法&#xff0c;用于從 Map 中獲取指定鍵的值&#xff0c;如果鍵不存在&#xff0c;則返回指定的默認值。 方法簽名如下&#xff1a; V getOrDefault(Object key, V defaultValue) 其中&#xff0c;key 是要獲取值的鍵&#xff0c;defaul…

day19_java泛型

泛型 Java 泛型&#xff08;generics&#xff09;是 JDK 5 中引入的一個新特性, 泛型提供了編譯時類型安全檢測機制&#xff0c;該機制允許程序員在編譯時檢測到非法的類型。保證了java的安全性 泛型的本質是參數化類型&#xff0c;也就是說所操作的數據類型被指定為一個參數…

AWS EC2使用 instance profile 訪問S3

AWS EC2 instance可以使用instance profile 配置訪問S3的權限。 然后就可以直接在EC2上執行 python代碼或者AWS CLI去訪問S3了。 唯一需要注意的地方是&#xff0c;申明region。 示例代碼&#xff1a; aws s3 ls xxxx-s3-bucket --region xxx-region import boto3 client …

一文讀懂MySQL基礎知識文集(8)

&#x1f3c6;作者簡介&#xff0c;普修羅雙戰士&#xff0c;一直追求不斷學習和成長&#xff0c;在技術的道路上持續探索和實踐。 &#x1f3c6;多年互聯網行業從業經驗&#xff0c;歷任核心研發工程師&#xff0c;項目技術負責人。 &#x1f389;歡迎 &#x1f44d;點贊?評論…

IDEA 報錯

IDEA 報錯&#xff1a; Cannot resolve symbol&#xff1a;這通常是由于 IDEA 無法識別您正在使用的類或方法導致的。請確保您已經導入了正確的包&#xff0c;并且您的類路徑設置正確。 NullPointerException&#xff1a;這通常是由于您的代碼嘗試訪問空對象或空值導致的。請檢…

JavaScript 函數的返回值

JavaScript 函數的返回值 JavaScript 函數的返回值是函數執行后返回的值&#xff0c;可以是任意類型的值&#xff0c;包括數字、字符串、布爾值、對象等。函數的返回值通過 return 關鍵字來指定&#xff0c;如果函數沒有指定返回值&#xff0c;則默認返回 undefined。例如&…

Qt處理焦點事件(獲得焦點,失去焦點)

背景&#xff1a; 我只是想處理焦點動作&#xff0c;由于懶&#xff0c;上網一搜&#xff0c;排名靠前的一位朋友&#xff0c;使用重寫部件的方式實現。還是因為懶&#xff0c;所以感覺復雜了。于是又花了一分鐘解決了一下。 所以記錄下來&#xff0c;以免以后忘了。 思路&a…

單目相機測距(3米范圍內)二維碼實現方案(python代碼 僅僅依賴opencv)

總體思路:先通過opencv 識別二維碼的的四個像素角位置,然后把二維碼的物理位置設置為 cv::Point3f(-HALF_LENGTH, -HALF_LENGTH, 0), //tl cv::Point3f(HALF_LENGTH, -HALF_LENGTH, 0), //tr cv::Point3f(HALF_LENGTH, HALF_LENGTH, 0), //br cv::P…

四年編程成長總結

文章目錄 計算機計算機基礎知識操作系統計算機網絡 自考學習與備考考試經歷 軟考學習與準備考試成果人生成長自主學習解決問題團隊合作 總結 計算機 計算機是我學習和應用Java編程的基礎&#xff0c;它為我提供了一個強大的工具和平臺。在這四年的學習中&#xff0c;我逐漸深入…

軟件運行原理 - 內存模型 - 棧內存

說明 C/C軟件運行時&#xff0c;內存根據使用方式的不同分為堆內存和棧內存&#xff0c;棧內存使用有以下特征&#xff1a; 棧內存使用&#xff08;申請、釋放&#xff09;由系統自動分配和釋放&#xff0c;程序員不用做任何操作。棧內存重復使用&#xff0c;進入函數時數據入…

什么是特征圖?

在卷積神經網絡&#xff08;CNN&#xff09;中&#xff0c;特征圖是在傳遞給卷積層的圖像上發生卷積操作后卷積層的輸出。 特征圖是如何形成的&#xff1f; 在上面的插圖中&#xff0c;我們可以看到特征圖是如何從提供的輸入圖像中形成的。 要發送到卷積層的圖像是一個包含像…

AutoSAR(基礎入門篇)1.2-AutoSAR的發展史

目錄 一、AutoSAR成員 二、AutoSAR歷史發展 三、未使用AutoSAR前的缺點 1、原始狀態

JavaScript 和 HTML DOM 參考手冊

JavaScript 和 HTML DOM 參考手冊 js的變量類型有字符串,布爾等 在操作這些變量類型的時候,可以將他們看成是對象來操作 因為js 把一切都封裝成對象來看 獲取字符串的長度 var str hello world; console.log(str.length); //11 console.log(str.substr(0,5)); // hello c…

微服務網關組件Gateway實戰

1. 需求背景 在微服務架構中&#xff0c;通常一個系統會被拆分為多個微服務&#xff0c;面對這么多微服務客戶端應該如何去調用呢&#xff1f;如果根據每個微服務的地址發起調用&#xff0c;存在如下問題&#xff1a; 客戶端多次請求不同的微服務&#xff0c;會增加客戶端代碼…