Arduino WIFI Shield V3点对点通信:AP+STA模式实现设备直连

Arduino WIFI Shield V3点对点通信:AP+STA模式实现设备直连 1. 项目概述两块WIFI Shield V3对联如果你手头正好有两块Arduino Uno和两块WIFI Shield V3扩展板想试试看它们之间能不能直接“对话”比如让一块板子控制另一块板子上的LED或者互相传递传感器数据那你来对地方了。这个“两块WIFI Shield V3对联”项目说白了就是让两个独立的Arduino节点通过它们各自的WIFI模块建立一个点对点的无线通信链路绕开传统的路由器或AP无线接入点。这听起来可能有点像让两部手机不通过基站直接建立蓝牙连接一样。为什么这么做想象一些实际场景你需要在一个没有现成Wi-Fi网络的环境下比如野外、大型仓库、临时展台让两个设备交换数据或者你想构建一个最小化的、私密的双向通信系统避免数据经过公共网络再或者你只是单纯想深入理解网络协议栈中“点对点”通信的底层原理。基于ESP8266芯片的WIFI Shield V3其核心固件本身就支持多种工作模式其中就包括我们需要的“Station”和“SoftAP”模式这为我们实现直接对联提供了硬件基础。这个项目适合已经熟悉Arduino基础编程如数字I/O、串口通信并对网络概念有初步了解的爱好者。整个过程会涉及到AT指令调试、网络 socket 编程、以及一些简单的数据包处理逻辑。虽然不涉及复杂的网页服务器或MQTT代理但能让你亲手搭建一个最精简的无线通信框架对理解物联网设备间如何“交谈”大有裨益。2. 核心通信模式与方案选型实现两块WIFI Shield V3对联本质上是在它们之间建立一个TCP或UDP连接。这需要其中一块板子扮演“接入点”AP或称SoftAP的角色另一块板子作为“站点”STA去连接这个AP。这是最稳定、最标准的实现方式。2.1 为何选择APSTA模式而非Ad-hoc你可能会想到另一种点对点模式Ad-hoc无线自组网。但这里不推荐。主要原因在于兼容性和稳定性。ESP8266的AT固件对Ad-hoc模式的支持并不完善甚至在某些版本中已被移除。而APSTA模式是ESP8266的核心功能经过充分测试文档齐全稳定性高。AP模式让一个Shield创建出一个微型Wi-Fi网络STA模式让另一个Shield像连接家里路由器一样去连接它逻辑清晰易于调试。2.2 通信协议选择TCP还是UDP确定了网络模式接下来要选择传输层协议。TCP传输控制协议像打电话。建立连接后能保证数据按顺序、可靠地送达。如果丢包它会自动重传。适合需要可靠传输的场景比如发送控制命令、传输文件。缺点是开销稍大建立连接有“三次握手”的过程。UDP用户数据报协议像寄明信片。无需建立连接直接发送。速度快开销小但不保证送达也不保证顺序。适合对实时性要求高、允许偶尔丢数据的场景如传感器流数据、实时状态广播。对于这个对联项目我强烈建议从TCP开始。因为它可靠编程模型简单类似串口更容易让你首次尝试就获得成功建立信心。我们后续的实操也将基于TCP。2.3 整体通信架构设计整个系统的数据流是这样的节点AAP服务器WIFI Shield设置为SoftAP模式创建一个Wi-Fi网络如MyDirectLink并启动一个TCP服务器监听特定端口例如8888。节点BSTA客户端WIFI Shield设置为STA模式扫描并连接到节点A创建的MyDirectLink网络然后作为TCP客户端向节点A的IP地址通常是192.168.4.1这是ESP8266 SoftAP的默认网关地址和端口8888发起连接请求。建立连接TCP三次握手成功后两者之间就建立了一条可靠的通信通道。数据交换此后A或B都可以通过这个Socket连接发送和接收数据。A的Arduino可以通过读取传感器将数据发送给BB的Arduino解析命令后可以控制LED或电机并将状态反馈回A。注意在APSTA模式下作为AP的节点A本身也可以同时作为STA去连接其他路由器但在这个纯对联项目中我们只使用其AP功能。作为客户端的节点B则专心做STA。3. 硬件连接与基础环境准备工欲善其事必先利其器。在写代码之前确保硬件和软件环境正确无误能避免很多后续的诡异问题。3.1 硬件清单与连接确认你需要准备Arduino Uno主板 x2WIFI Shield V3 扩展板 x2确保是V3版本基于ESP8266USB数据线 x2用于供电和编程电脑一台安装Arduino IDE若干杜邦线、LED、电阻、按键等用于验证通信可选但推荐连接步骤将两块WIFI Shield V3分别插入两块Arduino Uno。务必对准引脚轻轻压下确保所有排针都接触良好。这是最基础也最容易出问题的一步接触不良会导致串口通信失败。通过USB线将两块Arduino分别连接到电脑的两个USB口。如果端口不足也可以先连接一块调试好一块后再换另一块。WIFI Shield V3上通常有一个小开关用于选择MCUArduino与ESP8266的通信串口。确保开关拨到“UART”或“SW Serial”一侧具体看板子标注通常是远离USB口的那一侧。这个开关如果拨错Arduino就无法通过软串口向ESP8266发送AT指令了。3.2 Arduino IDE环境与关键库检查安装Arduino IDE从Arduino官网下载并安装最新稳定版如1.8.x或2.x。安装过程很简单一路下一步即可。安装ESP8266开发板支持非必须但推荐虽然我们是用AT指令控制但安装这个包可以确保IDE包含必要的串口驱动和示例。在“文件”-“首选项”的“附加开发板管理器网址”中添加http://arduino.esp8266.com/stable/package_esp8266com_index.json然后在“工具”-“开发板”-“开发板管理器”中搜索“esp8266”并安装。识别串口将Arduino通过USB连接电脑后在IDE的“工具”-“端口”菜单中你会看到新增的COM口Windows或/dev/cu.usbmodemXXXMac。记下两块板子对应的端口号编程时需要分别选择。3.3 至关重要的第一步AT指令测试在编写复杂的对联程序前必须单独测试每一块WIFI Shield是否响应AT指令。这能排除硬件连接、开关设置或板子本身的问题。在Arduino IDE中新建一个空白项目。将以下代码上传到第一块Arduino先不插WIFI Shield上传后再插上或者确保开关正确// 这是一个最简单的AT指令测试程序 // 使用SoftwareSerial与WIFI Shield通信 #include SoftwareSerial.h SoftwareSerial esp8266(2, 3); // RX, TX 连接Shield的TX, RX。根据你的Shield引脚可能不同常见是2,3或10,11请查阅你的Shield原理图 void setup() { Serial.begin(115200); // 电脑串口监视器 esp8266.begin(115200); // ESP8266默认AT固件波特率 Serial.println(Initializing...); delay(1000); // 发送测试指令 esp8266.println(AT); delay(100); } void loop() { // 从ESP8266读取数据并打印到电脑 if (esp8266.available()) { Serial.write(esp8266.read()); } // 从电脑串口输入指令发送给ESP8266 if (Serial.available()) { esp8266.write(Serial.read()); } }上传代码后打开串口监视器设置波特率为115200同时选择“Both NL CR”即换行和回车。在输入框发送AT你应该立刻看到回复OK。如果没收到OK请按以下顺序排查检查SoftwareSerial的引脚(2,3)是否与你的Shield实际连接匹配。这是最常见的错误。查看Shield的电路图或产品说明确认ESP8266的TX、RX分别接到了Arduino的哪两个数字引脚。检查WIFI Shield上的串口选择开关是否拨到了正确位置。尝试降低波特率如将esp8266.begin(115200)和串口监视器都改为9600或57600试试。检查USB供电是否充足尝试单独给Arduino Uno外接供电。实操心得务必为每块WIFI Shield单独进行此测试并记录下它们正常工作的SoftwareSerial引脚编号和波特率。两块板子的这些参数必须完全一致后续编程才能统一。我遇到过一块板子用(2,3)正常另一块却必须用(10,11)的情况就是因为不同批次的Shield布线略有不同。4. 核心代码实现与分步解析成功通过AT测试后我们就可以着手编写对联的核心代码了。我们将编写两个独立的Arduino程序一个用于AP服务器端一个用于STA客户端。4.1 AP服务器端代码实现与解析AP端的主要任务是创建Wi-Fi网络、启动TCP服务器、等待客户端连接、处理通信。// AP_Server.ino - WIFI Shield作为接入点和TCP服务器 #include SoftwareSerial.h // 根据你的测试结果修改这两个引脚 #define ESP8266_RX 2 #define ESP8266_TX 3 SoftwareSerial esp8266(ESP8266_RX, ESP8266_TX); // RX, TX const char* AP_SSID MyDirectLink_AP; // 你创建的AP名称 const char* AP_PASS 12345678; // AP密码至少8位 const int serverPort 8888; // TCP服务器监听端口 bool isConnected false; // 客户端连接状态标志 void setup() { Serial.begin(115200); esp8266.begin(115200); delay(1000); // 等待ESP8266启动 Serial.println(Setting up AP and Server...); // 1. 重置模块恢复初始状态可选但建议开始前执行 sendCommand(ATRST, 2000); delay(3000); // 等待重启 // 2. 设置为SoftAP模式 sendCommand(ATCWMODE2, 1000); // 模式2为SoftAP // 3. 配置AP参数SSID, 密码, 信道, 加密方式 String cmd ATCWSAP\; cmd AP_SSID; cmd \,\; cmd AP_PASS; cmd \,5,3; // 信道5加密方式3WPA2_PSK sendCommand(cmd, 3000); // 4. 启用多连接模式对于服务器是必须的 sendCommand(ATCIPMUX1, 1000); // 5. 在指定端口创建TCP服务器 cmd ATCIPSERVER1,; // 1表示创建服务器 cmd serverPort; sendCommand(cmd, 1000); // 6. 获取本地IP地址并打印 sendCommand(ATCIFSR, 1000); Serial.println(AP Server is ready!); Serial.print(SSID: ); Serial.println(AP_SSID); Serial.print(Password: ); Serial.println(AP_PASS); Serial.println(Waiting for client connection...); } void loop() { // 监听来自ESP8266的数据 if (esp8266.available()) { String response esp8266.readStringUntil(\n); Serial.println(- response); // 打印原始响应便于调试 // 检测是否有客户端连接 if (response.startsWith(IPD)) { // IPD,link ID,length:data isConnected true; Serial.println(Client Connected! Data incoming.); // 这里可以解析数据。例如简单打印数据内容 // 更复杂的解析需要根据协议来 int dataIndex response.indexOf(:); if (dataIndex ! -1) { String receivedData response.substring(dataIndex 1); receivedData.trim(); // 去除末尾换行 Serial.print(Received: ); Serial.println(receivedData); // 示例如果收到LED_ON可以控制本地LED需连接硬件 // if (receivedData LED_ON) { digitalWrite(LED_PIN, HIGH); } // 示例回复客户端 String reply Server got: receivedData; sendData(0, reply); // 0是服务器上客户端连接的链路ID } } // 检测连接断开 else if (response.indexOf(CLOSED) ! -1 || response.indexOf(ERROR) ! -1) { isConnected false; Serial.println(Client disconnected.); } } // 示例服务器也可以主动发送数据比如定时发送传感器读数 static unsigned long lastSend 0; if (isConnected millis() - lastSend 5000) { // 每5秒发送一次 lastSend millis(); String sensorValue String(analogRead(A0)); // 读取模拟引脚A0假设接了个电位器 sendData(0, A0: sensorValue); } } // 封装发送AT指令的函数 void sendCommand(String cmd, int waitTime) { Serial.println(- cmd); esp8266.println(cmd); delay(waitTime); // 可以在这里添加读取和打印响应的代码使调试信息更完整 } // 通过指定链路发送数据 void sendData(int linkId, String data) { String cmd ATCIPSEND; cmd linkId; cmd ,; cmd data.length(); esp8266.println(cmd); delay(50); // 等待模块回应 if (esp8266.find()) { esp8266.print(data); Serial.println(Sent: data); } else { Serial.println(Send failed: No prompt); } }代码关键点解析ATCWMODE2将WIFI模式设置为2SoftAP。模式1是STA模式3是APSTA混合。ATCWSAP设置AP的详细参数包括SSID、密码、信道和加密方式。加密方式“3”代表WPA2_PSK是目前最安全的个人加密方式。ATCIPMUX1启用多连接。对于TCP服务器必须设置为1即使你只连接一个客户端。ATCIPSERVER1,8888在端口8888上启动TCP服务器。“1”表示创建。ATCIFSR查询IP地址。SoftAP模式下模块自身的IP通常是192.168.4.1。IPD这是ESP8266接收到网络数据时通过串口主动上报给Arduino的指令。格式为IPD,link ID,length:data。解析这个字符串是获取客户端数据的关键。ATCIPSEND发送数据的指令。需要先指定链路ID和数据长度模块回复后再发送实际数据。4.2 STA客户端代码实现与解析客户端的主要任务是连接到AP、作为TCP客户端连接到服务器、发送数据、接收响应。// STA_Client.ino - WIFI Shield作为站点和TCP客户端 #include SoftwareSerial.h #define ESP8266_RX 2 #define ESP8266_TX 3 SoftwareSerial esp8266(ESP8266_RX, ESP8266_TX); const char* STA_SSID MyDirectLink_AP; // 要连接的AP名称必须与服务器端一致 const char* STA_PASS 12345678; // AP密码 const char* serverIP 192.168.4.1; // 服务器AP的IP地址通常是这个 const int serverPort 8888; bool connectedToServer false; void setup() { Serial.begin(115200); esp8266.begin(115200); delay(1000); Serial.println(STA Client Starting...); // 1. 重置 sendCommand(ATRST, 2000); delay(3000); // 2. 设置为STA模式 sendCommand(ATCWMODE1, 1000); // 模式1为STA // 3. 连接到指定的AP String cmd ATCWJAP\; cmd STA_SSID; cmd \,\; cmd STA_PASS; cmd \; sendCommand(cmd, 5000); // 连接可能需要较长时间 // 4. 获取本地IP确认连接成功 sendCommand(ATCIFSR, 1000); // 5. 启用单连接客户端模式通常用单连接 sendCommand(ATCIPMUX0, 1000); // 6. 建立TCP连接到服务器 cmd ATCIPSTART\TCP\,\; cmd serverIP; cmd \,; cmd serverPort; sendCommand(cmd, 3000); // 检查连接是否成功 delay(1000); if (esp8266.find(CONNECT)) { connectedToServer true; Serial.println(Connected to Server!); } else { Serial.println(Connection to server failed.); } } void loop() { // 接收来自服务器的数据 if (esp8266.available()) { String response esp8266.readStringUntil(\n); // 客户端模式下接收到的数据也是以IPD开头 if (response.startsWith(IPD)) { int dataIndex response.indexOf(:); if (dataIndex ! -1) { String serverData response.substring(dataIndex 1); serverData.trim(); Serial.print(From Server: ); Serial.println(serverData); // 这里可以解析服务器指令并执行例如控制LED } } } // 示例客户端定时发送数据比如读取一个按钮状态 static unsigned long lastSend 0; if (connectedToServer millis() - lastSend 3000) { lastSend millis(); // 假设数字引脚4连接了一个按钮上拉电阻按下为LOW int buttonState digitalRead(4); String message BTN: String(buttonState); sendData(message); Serial.println(Sent: message); } // 示例从串口监视器输入发送给服务器 if (Serial.available()) { String input Serial.readStringUntil(\n); input.trim(); if (input.length() 0 connectedToServer) { sendData(input); } } } void sendCommand(String cmd, int waitTime) { Serial.println(- cmd); esp8266.println(cmd); delay(waitTime); } // 客户端模式下发送数据单连接链路ID默认为0 void sendData(String data) { String cmd ATCIPSEND; cmd data.length(); esp8266.println(cmd); delay(50); if (esp8266.find()) { esp8266.print(data); } else { Serial.println(Send failed.); } }代码关键点解析ATCWMODE1设置为站点STA模式。ATCWJAP加入无线网络。这是客户端最关键的步骤必须确保SSID和密码与服务器端创建的AP完全一致。ATCIPMUX0客户端模式使用单连接即可。ATCIPSTART发起TCP连接。指定协议“TCP”、服务器IP地址和端口号。CONNECT成功建立TCP连接后ESP8266会返回此信息。5. 烧录、调试与功能验证代码编写完成后真正的挑战才刚刚开始烧录、调试和让整个系统跑起来。5.1 分步烧录与上电顺序先烧录AP服务器端在Arduino IDE中选择对应的端口COM X将AP_Server.ino上传到第一块Arduino Uno。再烧录STA客户端端更换端口COM Y将STA_Client.ino上传到第二块Arduino Uno。上电顺序务必先给AP服务器端上电等待其串口监视器输出“AP Server is ready! Waiting for client connection...”。然后再给STA客户端上电。这是因为客户端启动后需要立即能找到并连接AP如果AP还没创建好客户端就会连接失败。打开两个串口监视器分别打开对应两个端口的串口监视器波特率均设为115200。你将看到类似以下的日志服务器端显示AP创建成功IP地址然后等待连接。当客户端连接后会打印“Client Connected!”。客户端端显示连接AP成功获取到IP通常是192.168.4.x然后打印“Connected to Server!”。5.2 基础通信验证连接建立后你可以通过以下方式验证通信客户端主动发送在客户端的loop函数中我们设置了每3秒发送一次按钮状态BTN:0或BTN:1。观察服务器端串口应该能周期性地收到这些消息并打印“Received: BTN:x”同时回复“Server got: BTN:x”。在客户端串口也能看到来自服务器的回复“From Server: Server got: BTN:x”。服务器主动发送服务器端每5秒发送一次模拟引脚A0的值。在客户端串口能看到“From Server: A0:xxx”。手动发送在客户端的串口监视器输入框输入任意字符串如“HelloAP”然后发送。在服务器端串口监视器应能看到接收到的信息。5.3 硬件联动验证让控制真实发生为了更有成就感我们可以添加简单的硬件控制在服务器端定义一个LED引脚如13板载LED。在解析接收数据的部分添加判断if (receivedData LED_ON) { digitalWrite(13, HIGH); sendData(0, LED is ON); } else if (receivedData LED_OFF) { digitalWrite(13, LOW); sendData(0, LED is OFF); }记得在setup()里用pinMode(13, OUTPUT);初始化引脚。在客户端端连接一个真正的按钮到引脚4使用上拉电阻按下接地。当检测到按钮按下buttonState从HIGH变为LOW时除了发送BTN:0还可以额外发送“LED_ON”指令。int lastButtonState HIGH; int currentButtonState digitalRead(4); if (lastButtonState HIGH currentButtonState LOW) { sendData(LED_ON); // 发送开灯指令 delay(50); // 消抖 } lastButtonState currentButtonState;现在按下客户端的按钮你应该能看到服务器端的板载LED亮起并且串口有相应的交互日志。这就完成了一个完整的“无线遥控”闭环。6. 深度优化、稳定性提升与常见问题排查项目能跑通只是第一步要让其稳定、可靠、实用还需要进行一系列优化和问题排查。6.1 通信稳定性优化策略原始的代码为了清晰使用了大量delay()这在简单演示中可以但在实际应用中会阻塞程序导致响应迟钝或丢失数据。我们需要优化状态机与非阻塞处理将AT指令的发送与响应解析改为基于状态机的非阻塞方式。例如定义一个commandState变量在loop()中根据状态执行不同步骤用millis()管理超时而不是delay()。数据帧封装与解析目前我们发送的是纯文本字符串如“BTN:0”。在复杂应用中建议定义简单的数据帧协议。例如可以规定每帧数据以{开始以}结束内部用逗号分隔指令和参数{LED,ON}或{SENSOR,A0,512}。在接收端需要编写一个解析器来按帧提取和解析数据避免粘包多个数据包连在一起和断包一个包被拆开接收问题。增加心跳机制在TCP连接中长时间没有数据交换中间网络设备虽然这里直连但习惯养成可能会断开连接。可以让客户端或服务器定时如每30秒发送一个心跳包如“PING”对方回复“PONG”。如果连续几次收不到心跳回复则认为连接断开尝试重新初始化连接。缓冲区管理readStringUntil在数据量大时可能不够可靠。可以改为使用字符缓冲区逐个读取并判断帧的完整性。6.2 高级功能扩展思路当基础通信稳定后你可以尝试双向控制不仅客户端控制服务器服务器也可以主动控制客户端。只需在两端都实现指令解析和执行逻辑。多客户端连接修改服务器端代码利用ATCIPMUX1和多链路ID可以允许多个STA客户端同时连接。需要维护一个连接列表并正确地为每个链路ID发送数据。切换为UDP通信将ATCIPSTART中的 “TCP” 改为 “UDP”并指定本地和远程端口。UDP无需连接发送指令变为ATCIPSENDlength数据会发往最后一次ATCIPSTART指定的远端。适合广播或高速数据流。混合模式APSTA将一方的ATCWMODE设为3。这样该设备既能作为AP让另一方连接又能作为STA去连接你家中的路由器从而将这对联系统接入互联网实现远程控制。6.3 典型问题排查速查表遇到问题时请按此表顺序排查问题现象可能原因排查步骤与解决方案串口无任何输出AT指令无回复1. 电源问题2. 串口引脚接错3. 波特率不对4. 开关位置错误1. 检查USB线是否插紧尝试外接电源。2.重点检查SoftwareSerial的RX/TX引脚定义是否与Shield实际接线匹配。用万用表通断档测量。3. 尝试常见的波特率9600, 57600, 115200。4. 确认WIFI Shield上的MCU/ESP串口选择开关拨到了正确位置。AT指令回复ERROR或busy1. 上一条指令未执行完2. 指令格式错误3. 模块未就绪1. 在关键指令后增加足够的delay或等待收到OK后再发下一条。2. 仔细核对AT指令格式特别是引号、逗号、反斜杠。使用Serial.println打印出发送的指令确认。3. 发送AT测试确保返回OK后再进行后续配置。STA客户端连接AP失败1. SSID/密码错误2. 信号弱或AP未启动3. 加密方式不匹配1. 双重检查AP_SSID和AP_PASS在两端代码中是否完全一致包括大小写和空格。2. 确保服务器端AP已成功创建串口有输出。将两台设备靠近。3. 确保服务器ATCWSAP中加密方式参数正确通常用3。STA客户端连接服务器失败 (ATCIPSTART失败)1. 服务器IP或端口错误2. 服务器未启动监听3. 防火墙/网络设置问题1. 确认服务器端IP是否为192.168.4.1可在服务器串口用ATCIFSR查询。确认端口号一致。2. 确认服务器端已执行ATCIPSERVER1,8888且返回OK。3. 点对点网络一般无此问题。连接成功但收不到数据1. 数据解析逻辑错误2. 数据发送格式不对3. 硬件流控问题罕见1.重点检查loop()中解析IPD的代码。打印出完整的response字符串观察其格式。2. 确认发送数据前是否成功收到了提示符。发送的数据长度是否与ATCIPSEND声明的长度一致。3. 尝试在SoftwareSerial初始化后添加esp8266.setTimeout(100);。通信一段时间后断开1. 无心跳连接被释放2. 电源不稳定3. 代码逻辑缺陷导致崩溃1. 实现简单的心跳包机制。2. 确保供电充足特别是当连接执行器如电机时需单独供电。3. 检查是否有数组越界、内存泄漏。简化代码逐步添加功能测试。避坑技巧调试时务必让两个串口监视器同时运行。将服务器和客户端的串口日志同时摆在面前是诊断通信问题最直观的方式。你可以清晰地看到指令发出、响应返回、连接建立、数据流动的每一个环节哪里卡住了、哪里报错了一目了然。7. 从项目实践中获得的体会折腾完这个项目我最深的体会是物联网的起点往往就是这种最朴素的设备间直连。它剥离了云平台、路由器的复杂性让你能聚焦在通信协议本身。ATCIPSEND后等待的那个瞬间数据通过无线电波从一块板子飞到另一块板子这种掌控感是调用现成物联网库所无法比拟的。过程中最折磨人也最有收获的部分绝对是调试。尤其是当串口一片寂静或者满是ERROR的时候。我总结出的黄金法则是化整为零分段验证。不要试图一次性写完所有功能然后祈祷它运行。先确保AT指令能通再确保AP能建接着确保STA能连最后再处理数据收发。每完成一步就庆祝一下这能极大保持你的耐心和信心。另一个重要的心得是关于电源。ESP8266在发射Wi-Fi信号时峰值电流可能超过200mA而Arduino Uno的3.3V线性稳压器输出能力有限。如果你发现模块工作时断时续或者复位强烈建议给WIFI Shield进行独立供电或者使用带有更大电流3.3V稳压器的Arduino板如Arduino Mega或者直接使用USB外接电源。稳定的电源是一切数字系统可靠工作的基石。最后这个“对联”项目是一个完美的跳板。理解了它你再去看ESP8266的Station模式连接家里路由器、SoftAP模式提供配置页面、甚至Deep Sleep低功耗应用都会觉得脉络清晰。你还可以把代码里的字符串指令替换成更高效的二进制协议或者尝试用ESP-NOW这种更底层的协议实现更低延迟的对联。这条路才刚刚开始。