ardunio WiFi連接模板
ardunio R4 WiFi 開發板有著不錯的性能和板載內存,本機自帶 WiFi 連接模塊,可以完成簡單的網絡服務。對于這個小東西我情有獨鐘,也總希望能夠用它來做些什么,所以先從 WiFi 連接開始學起,未來考慮一步一步為它接入大模型服務,做出一個小的桌面顯示小玩具。
WiFiClient
只能訪問簡單的http鏈接
ardunio R4 WiFi開發板依賴WiFiS3.h
庫進行網絡連接。同時,最好新建一個保存密鑰的頭文件保存WiFi名稱和密碼。
使用WiFiClient
聲明client
對象,用于表示一個TCP/IP客戶端(類似于網絡套接字)。并聲明WiFi連接狀態status
,初始化為WL_IDLE_STATUS
。WifiS3
庫內置如下幾種WiFi連接狀態:
WL_NO_SHIELD
** / **WL_NO_MODULE
:沒有檢測到WiFi模塊。WL_IDLE_STATUS
:WiFi模塊處于空閑狀態。WL_NO_SSID_AVAIL
:沒有可用的SSID。WL_SCAN_COMPLETED
:WiFi掃描完成。WL_CONNECTED
:成功連接到WiFi網絡。WL_CONNECT_FAILED
:連接失敗。WL_CONNECTION_LOST
:連接丟失。WL_DISCONNECTED
:斷開連接。WL_AP_LISTENING
:WiFi模塊作為接入點監聽中。WL_AP_CONNECTED
:設備已連接到WiFi模塊作為接入點。WL_AP_FAILED
:接入點模式啟動失敗。
WiFiClient client;
int status = WL_IDLE_STATUS;
之后在setup
中配置網絡連接初始化:聲明波特率 → WiFi連接 → 嘗試連接直到成功 → 打印IP。
void setup() {Serial.begin(115200);delay(1000);Serial.println("Connecting to WiFi");WiFi.begin(ssid, pass); //WifiS3庫已經內置WiFi全局變量,可以直接使用while(WiFi.status() != WL_CONNECTED){delay(500);Serial.print(".");}Serial.println("Connected to WiFi");Serial.println("IP Address: ");Serial.println(WiFi.localIP());}
WiFiSSLClient
可以訪問https安全鏈接
WiFiClient
只能訪問基礎的http連接,想要允許 Arduino 設備通過 WiFi 網絡與支持 SSL/TLS 加密的服務器建立安全連接,從而安全地發送和接收數據需要使用WiFiSSLClient
類。它的使用方法和WiFiClient
相似,只需改為聲明WiFiSSLClient client;
。
為了向服務器發送請求,我們使用如下方式添加請求內容:
if (client.connect(server, 443)) {Serial.println("connected to server");client.println("GET / HTTP/1.1");client.println("Host: www.google.com");client.println("Connection: close");client.println();
}
client.connect(server, 443)
這行代碼嘗試通過TCP/IP協議連接到目標服務器的443端口(HTTPS默認端口)。如果連接成功,說明Arduino已經與網頁服務器建立了通信通道。
client.println()
是用來向服務器發送HTTP請求,GET / HTTP/1.1
表示請求根路徑(/
)的內容,使用HTTP 1.1協議;**Host: www.google.com
指定目標主機名;Connection: close
**告訴服務器在響應完成后關閉連接。
請求完成,我們可以使用如下方式查看服務器響應內容:
void read_response() {uint32_t received_data_num = 0;while (client.available()) {/* actual data reception */char c = client.read();/* print data to serial port */Serial.print(c);/* wrap data to 80 columns*/received_data_num++;if(received_data_num % 80 == 0) {Serial.println();}}
}
參考完整示例,訪問少數派文章為Claude桌面端集成tavily搜索 - 少數派
/*TLS WiFi Web client - 訪問少數派文章Board CA Root certificate bundle is embedded inside WiFi firmware:https://github.com/arduino/uno-r4-wifi-usb-bridge/blob/main/certificates/cacrt_all.pem
*/#include "WiFiS3.h"
#include "WiFiSSLClient.h"
#include "IPAddress.h"#include "secret.h"///please enter your sensitive data in the Secret tab/arduino_secrets.h
char ssid[] = SECRET_SSID; // your network SSID (name)
char pass[] = SECRET_PASS; // your network password (use for WPA, or use as key for WEP)int status = WL_IDLE_STATUS;
// 修改為少數派網站
char server[] = "sspai.com"; // 少數派網站域名// Initialize the SSL client
WiFiSSLClient client;/* -------------------------------------------------------------------------- */
void setup() {
/* -------------------------------------------------------------------------- *///Initialize serial and wait for port to open:Serial.begin(115200);while (!Serial) {; // wait for serial port to connect. Needed for native USB port only}// check for the WiFi module:if (WiFi.status() == WL_NO_MODULE) {Serial.println("Communication with WiFi module failed!");// don't continuewhile (true);}String fv = WiFi.firmwareVersion();if (fv < WIFI_FIRMWARE_LATEST_VERSION) {Serial.println("Please upgrade the firmware");}// attempt to connect to WiFi network:while (status != WL_CONNECTED) {Serial.print("Attempting to connect to SSID: ");Serial.println(ssid);// Connect to WPA/WPA2 network.status = WiFi.begin(ssid, pass);// wait 10 seconds for connection:delay(10000);}printWifiStatus();Serial.println("\nStarting connection to sspai.com...");// if you get a connection, report back via serial:if (client.connect(server, 443)) {Serial.println("connected to server");// Make a HTTP request for the specific article:client.println("GET /post/97248 HTTP/1.1");client.println("Host: sspai.com");client.println("User-Agent: Mozilla/5.0 (compatible; Arduino/1.0)"); // 添加更友好的User-Agentclient.println("Accept: text/html"); // 接受HTML內容client.println("Connection: close");client.println();} else {Serial.println("Connection to server failed");}
}/* just wrap the received data up to 80 columns in the serial print*/
/* -------------------------------------------------------------------------- */
void read_response() {
/* -------------------------------------------------------------------------- */uint32_t received_data_num = 0;while (client.available()) {/* actual data reception */char c = client.read();/* print data to serial port */Serial.print(c);/* wrap data to 80 columns*/received_data_num++;if(received_data_num % 80 == 0) {Serial.println();}}
}/* -------------------------------------------------------------------------- */
void loop() {
/* -------------------------------------------------------------------------- */read_response();// if the server's disconnected, stop the client:if (!client.connected()) {Serial.println();Serial.println("disconnecting from server.");client.stop();// do nothing forevermore:while (true);}
}/* -------------------------------------------------------------------------- */
void printWifiStatus() {
/* -------------------------------------------------------------------------- */// print the SSID of the network you're attached to:Serial.print("SSID: ");Serial.println(WiFi.SSID());// print your board's IP address:IPAddress ip = WiFi.localIP();Serial.print("IP Address: ");Serial.println(ip);// print the received signal strength:long rssi = WiFi.RSSI();Serial.print("signal strength (RSSI):");Serial.print(rssi);Serial.println(" dBm");
}
串口打印示例:
14:11:22.536 -> SSID: ZTE_2AED09
14:11:22.536 -> IP Address: 192.168.0.5
14:11:22.578 -> signal strength (RSSI):-51 dBm
14:11:22.578 ->
14:11:22.578 -> Starting connection to sspai.com...
14:11:23.804 -> connected to server
14:11:24.536 -> HTTP/1.1 200 OK
14:11:24.536 -> Date: Thu, 13 Mar 2025 06:11:22 GMT
14:11:24.536 -> Content-Type: text/html; c
14:11:24.536 -> harset=utf-8
14:11:24.536 -> Content-Length: 119824
14:11:24.536 -> Connection: close
14:11:24.536 -> Vary: Accept-Encoding
14:11:24.536 ->
14:11:24.536 -> Cache-Control: no-store
14:11:24.536 ->
14:11:24.536 -> <!DOCTYPE html>
14:11:24.536 -> <html lang="zh-CN" id="html">
14:11:24.536 -> <head>
14:11:24.536 ->
14:11:24.536 -> <meta charset="utf-8">
14:11:24.536 -> <meta name="viewport" content="width=device-width, us
14:11:24.536 -> er-scalable=no, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0, viewpor
14:11:24.568 -> t-fit=cover">
14:11:24.568 -> <meta name="theme-color" content="" />
14:11:24.568 -> <meta
14:11:24.568 -> http-equiv="C
14:11:24.568 -> ontent-Security-Policy"
14:11:24.568 -> content="frame-src https://sspai.com https://*.sspai
14:11:24.568 -> .com https://*.bilibili.com https://bilibili.com https://v.qq.com https://embed.
14:11:24.568 -> music.apple.com https://jinshuju.net https://share.newsroom.apple;"
14:11:24.607 -> >
14:11:24.607 -> <meta
14:11:24.607 -> name="fragment" content="!">
14:11:24.607 -> <link rel="shortcut icon" href="https://cdn-stati
14:11:24.607 -> c.sspai.com/favicon/sspai.ico" type="image/x-icon" />
14:11:24.607 -> <link rel="icon" href="h...14:11:48.951 -> var _hmt = _hmt || []
14:11:48.951 -> ;
14:11:48.951 -> (function () {
14:11:48.951 -> var hm = document.createElement("script");
14:11:48.951 -> hm.s
14:11:48.951 -> rc = "//hm.baidu.com/hm.js?92174dab8163cf598817a93d11d5c588";
14:11:48.984 -> var s = docu
14:11:48.984 -> ment.getElementsByTagName("script")[0];
14:11:48.984 -> s.parentNode.insertBefore(hm, s);
14:11:48.984 ->
14:11:48.984 -> })();
14:11:48.984 ->
14:11:48.984 -> </script>
14:11:48.984 -> <!-- Baidu Push -->
14:11:48.984 -> <script>
14:11:48.984 -> (function () {
14:11:48.984 ->
14:11:48.984 -> var bp = document.createElement('script');
14:11:48.984 -> var curProtocol = window.locat
14:11:48.984 -> ion.protocol.split(':')[0];
14:11:48.984 -> if (curProtocol === 'https') {
14:11:48.984 -> bp.src
14:11:48.984 -> = 'https://zz.bdstatic.com/linksubmit/push.js';
14:11:48.984 -> } else {
14:11:49.025 -> bp.src =
14:11:49.025 -> 'http://push.zhanzhang.baidu.com/push.js';
14:11:49.025 -> }
14:11:49.025 -> var s = document.getEle
14:11:49.025 -> mentsByTagName("script")[0];
14:11:49.058 -> s.parentNode.insertBefore(bp, s);
14:11:49.058 -> })();
14:11:49.058 ->
14:11:49.058 -> </script>
14:11:49.058 -> </body>
14:11:49.058 -> </html>
14:11:49.058 ->
14:11:49.058 -> disconnecting from server.
WiFiServer
把ardunio作為服務器
ardunio同樣可以作為服務器使用,提供瀏覽器以http訪問IP的能力。它的交互過層如下:
- 瀏覽器(客戶端)連接到Arduino的IP地址
- 瀏覽器發送HTTP請求
- Arduino處理請求并返回網頁內容
- 瀏覽器接收內容并斷開連接
- Arduino在串口打印“客戶端斷開連接”
通過聲明WiFiServer server(80);
來定義服務器。之后,使用server.begin();
啟動服務器。主循環參考如下:
void loop() {// 檢查是否有新的客戶端連接WiFiClient client = server.available();if (client) {Serial.println("新客戶連接");String currentLine = ""; // 用于存儲當前讀取的HTTP請求行// 當客戶端保持連接時持續處理while (client.connected()) {// 檢查是否有數據可讀if (client.available()) {// 逐字符讀取HTTP請求char c = client.read();Serial.write(c); // 將讀取的字符輸出到串口監視器// 處理換行符if (c == '\n') {// 空行標志著HTTP請求頭的結束if (currentLine.length() == 0) {sendHttpResponse(client); // 發送HTTP響應break; // 退出處理循環} else {currentLine = ""; // 重置當前行,準備讀取下一行}} else if (c != '\r') { // 忽略回車符currentLine += c; // 將字符添加到當前行}}}delay(1); // 短暫延時確保數據傳輸完成client.stop(); // 關閉客戶端連接Serial.println("客戶端斷開連接");}
}
當瀏覽器向ardunio發送請求時,ardunio服務器會向客戶端發送HTTP響應,通過自定義的sendHttpResponse
函數封裝了這個響應,它具體如下:
void sendHttpResponse(WiFiClient &client) {// 發送HTTP頭client.println("HTTP/1.1 200 OK");client.println("Content-Type: text/html; charset=UTF-8");client.println("Connection: close");client.println();// 發送HTML內容client.print(HTML_HEADER);// 可以在這里處理動態內容替換String content = HTML_CONTENT;content.replace("%SERVER_TIME%", String(millis() / 1000));client.print(content);client.print(HTML_FOOTER);
}
client.println("HTTP/1.1 200 OK");
:這行代碼發送HTTP狀態行。 HTTP/1.1 表示使用的HTTP協議版本, 200 是狀態碼,代表請求已成功處理, OK 是狀態碼對應的文本描述。客戶端收到這個狀態行后,就知道請求已經成功處理。client.println("Content-Type: text/html; charset=UTF-8");
:這行代碼發送 Content-Type 頭部。它告訴客戶端響應內容的類型是HTML,并且使用的字符編碼是UTF - 8。這樣客戶端就能正確解析和顯示響應內容。client.println("Connection: close");
:這行代碼發送 Connection 頭部。 close 表示在響應完成后,服務器會關閉與客戶端的連接。這是一種常見的做法,特別是在處理簡單的HTTP請求時。client.println();
:這行代碼發送一個空行。在HTTP協議中,空行用于分隔頭部和主體。發送空行后,后續發送的內容就是響應的主體部分了。
服務器完整示例如下
#include "WiFiS3.h"
#include "IPAddress.h"
#include "secret.h" // 確保創建此文件
#include "html_content.h"// 在arduino_secrets.h中定義您的網絡憑據
// #define SECRET_SSID "ZTE_2AED09"
// #define SECRET_PASS "您的密碼"
char ssid[] = SECRET_SSID;
char pass[] = SECRET_PASS;int status = WL_IDLE_STATUS;
WiFiServer server(80);void setup() {// 初始化串口通信Serial.begin(115200);while (!Serial) {; // 等待串口連接}Serial.println("Arduino Web Server啟動");// 檢查WiFi模塊if (WiFi.status() == WL_NO_MODULE) {Serial.println("WiFi模塊通信失敗!");while (true); // 不繼續}// 檢查固件版本String fv = WiFi.firmwareVersion();Serial.print("WiFi固件版本: ");Serial.println(fv);if (fv < WIFI_FIRMWARE_LATEST_VERSION) {Serial.println("請升級固件");}// 連接到WiFi網絡while (status != WL_CONNECTED) {Serial.print("嘗試連接到SSID: ");Serial.println(ssid);// 連接到WPA/WPA2網絡status = WiFi.begin(ssid, pass);// 等待10秒連接delay(10000);}// 打印WiFi狀態printWifiStatus();// 啟動服務器server.begin();Serial.println("服務器已啟動");
}void loop() {// 檢查是否有新的客戶端連接WiFiClient client = server.available();if (client) {Serial.println("新客戶連接");String currentLine = ""; // 用于存儲當前讀取的HTTP請求行// 當客戶端保持連接時持續處理while (client.connected()) {// 檢查是否有數據可讀if (client.available()) {// 逐字符讀取HTTP請求char c = client.read();Serial.write(c); // 將讀取的字符輸出到串口監視器// 處理換行符if (c == '\n') {// 空行標志著HTTP請求頭的結束if (currentLine.length() == 0) {sendHttpResponse(client); // 發送HTTP響應break; // 退出處理循環} else {currentLine = ""; // 重置當前行,準備讀取下一行}} else if (c != '\r') { // 忽略回車符currentLine += c; // 將字符添加到當前行}}}delay(1); // 短暫延時確保數據傳輸完成client.stop(); // 關閉客戶端連接Serial.println("客戶端斷開連接");}
}void sendHttpResponse(WiFiClient &client) {// 發送HTTP頭client.println("HTTP/1.1 200 OK");client.println("Content-Type: text/html; charset=UTF-8");client.println("Connection: close");client.println();// 發送HTML內容client.print(HTML_HEADER);// 可以在這里處理動態內容替換String content = HTML_CONTENT;content.replace("%SERVER_TIME%", String(millis() / 1000));client.print(content);client.print(HTML_FOOTER);
}void printWifiStatus() {// 打印SSIDSerial.print("SSID: ");Serial.println(WiFi.SSID());// 打印IP地址IPAddress ip = WiFi.localIP();Serial.print("IP Address: ");Serial.println(ip);// 打印信號強度long rssi = WiFi.RSSI();Serial.print("signal strength (RSSI):");Serial.print(rssi);Serial.println(" dBm");// 顯示訪問鏈接Serial.println();Serial.print("在瀏覽器中訪問 http://");Serial.println(ip);
}
http網頁
#ifndef HTML_CONTENT_H
#define HTML_CONTENT_H// HTML頭部
const char HTML_HEADER[] PROGMEM = R"rawliteral(
<!DOCTYPE html>
<html>
<head><meta charset="UTF-8"><title>Arduino Web服務器</title><style>body {font-family: Arial, sans-serif;margin: 20px;text-align: center;background-color: #f0f0f0;}h1 {color: #0066cc;}.container {max-width: 800px;margin: 0 auto;background-color: white;padding: 20px;border-radius: 8px;box-shadow: 0 2px 4px rgba(0,0,0,0.1);}</style>
</head>
<body><div class="container">
)rawliteral";// 主要內容
const char HTML_CONTENT[] PROGMEM = R"rawliteral(<h1>Arduino Web服務器</h1><p>歡迎訪問Arduino UNO R4 WiFi服務器!</p><p>服務器運行正常</p><p>當前時間: <span id="server-time">%SERVER_TIME%</span></p>
)rawliteral";// 底部
const char HTML_FOOTER[] PROGMEM = R"rawliteral(</div>
</body>
</html>
)rawliteral";#endif
串口打印
打開瀏覽器,訪問http://192.168.0.5