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