ESP32 Web Server串口数据周期性更新问题求助
解决ESP32通过UART获取数据并周期性更新Web接口的问题
首先咱们先拆解下你当前代码的核心问题:
readuart()函数每次只读取单个字符,既没处理串口缓冲区里可能存在的多字符数据,也没保留最新的串口数据状态——每次请求接口时,只会读取当下串口的一个字符,之后就没有后续更新了。- HTTP GET请求是单次响应模式,客户端请求一次,服务器返回一次数据就结束连接,不会主动给客户端推送新数据。
下面给你两种实用的解决方案,按需选择:
方案一:客户端周期性请求(简单易上手)
这个方案适合对实时性要求不高的场景,让前端页面每隔一段时间自动重新请求接口,获取最新的串口数据。同时我们要优化串口数据的读取逻辑,确保能拿到完整的串口数据(比如读取到换行符为止)。
步骤1:优化串口读取逻辑+新增前端自动刷新页面
修改后的完整代码如下:
#include <WiFi.h> #include "ESPAsyncWebServer.h" AsyncWebServer server1(81); const char* ssid ="mywifi"; const char* password ="mywifipass"; // 存储最新的完整串口数据 String latestUartData = ""; void readUart() { while (Serial.available() > 0) { char c = Serial.read(); // 假设串口数据以换行符结尾,读取完整一行数据 if (c == '\n') { // 去掉多余的换行/回车符 latestUartData.trim(); Serial.print("收到完整数据: "); Serial.println(latestUartData); } else { latestUartData += c; } } } void setup() { Serial.begin(115200); WiFi.begin(ssid, password); while (WiFi.status() != WL_CONNECTED) { delay(1000); Serial.println("正在连接WiFi.."); } Serial.println("已连接WiFi网络"); Serial.println(WiFi.localIP()); // 提供纯文本数据接口 server1.on("/test_data", HTTP_GET, [](AsyncWebServerRequest *request){ request->send(200, "text/plain", latestUartData.c_str()); }); // 提供带自动刷新功能的HTML页面 server1.on("/", HTTP_GET, [](AsyncWebServerRequest *request){ String html = R"HTML( <!DOCTYPE html> <html> <body> <h1>UART实时数据</h1> <p id="data">等待数据...</p> <script> // 每隔1秒请求一次最新数据并更新页面 setInterval(() => { fetch('/test_data') .then(response => response.text()) .then(data => { document.getElementById('data').textContent = data; }); }, 1000); </script> </body> </html> )HTML"; request->send(200, "text/html", html); }); server1.begin(); } void loop() { // 循环读取串口数据,实时更新latestUartData readUart(); }
说明:
- 新增
latestUartData变量存储最新的完整串口数据,readUart()函数会在loop()中持续运行,读取串口缓冲区的所有字符,直到遇到换行符完成一次完整数据的读取。 - 根路径
/的HTML页面用JavaScript的setInterval每隔1秒自动请求/test_data接口,更新页面显示的内容。
方案二:使用Server-Sent Events(SSE)主动推送(更实时)
如果需要低延迟的实时更新,SSE是更好的选择——服务器会主动向客户端推送新数据,不需要客户端反复发起请求,保持长连接即可。
修改后的完整代码:
#include <WiFi.h> #include "ESPAsyncWebServer.h" AsyncWebServer server1(81); const char* ssid ="mywifi"; const char* password ="mywifipass"; String latestUartData = ""; bool newDataAvailable = false; // 标记是否有新的串口数据 void readUart() { while (Serial.available() > 0) { char c = Serial.read(); if (c == '\n') { latestUartData.trim(); newDataAvailable = true; // 标记有新数据待推送 Serial.print("收到新数据: "); Serial.println(latestUartData); } else { latestUartData += c; } } } void setup() { Serial.begin(115200); WiFi.begin(ssid, password); while (WiFi.status() != WL_CONNECTED) { delay(1000); Serial.println("正在连接WiFi.."); } Serial.println("已连接WiFi网络"); Serial.println(WiFi.localIP()); // SSE推送接口,保持长连接主动发数据 server1.on("/stream", HTTP_GET, [](AsyncWebServerRequest *request){ // 设置SSE专属响应头 AsyncWebServerResponse *response = request->beginResponseStream("text/event-stream"); response->addHeader("Cache-Control", "no-cache"); response->addHeader("Connection", "keep-alive"); request->send(response); // 持续监听新数据,有新数据就推送给客户端 while (WiFi.status() == WL_CONNECTED) { if (newDataAvailable) { // SSE消息格式:data: 内容\n\n response->print("data: "); response->print(latestUartData); response->print("\n\n"); response->send(); // 发送数据 newDataAvailable = false; // 重置标记 } delay(100); // 避免占用过多CPU资源 } }); // 提供SSE前端页面 server1.on("/", HTTP_GET, [](AsyncWebServerRequest *request){ String html = R"HTML( <!DOCTYPE html> <html> <body> <h1>UART实时数据(SSE主动推送)</h1> <p id="data">等待数据...</p> <script> // 建立SSE长连接 const eventSource = new EventSource('/stream'); // 接收服务器推送的新数据 eventSource.onmessage = function(event) { document.getElementById('data').textContent = event.data; }; // 处理连接异常 eventSource.onerror = function(error) { console.error('SSE连接出错:', error); eventSource.close(); }; </script> </body> </html> )HTML"; request->send(200, "text/html", html); }); server1.begin(); } void loop() { readUart(); }
说明:
- SSE是基于HTTP的服务器主动推送技术,客户端和服务器保持长连接,当服务器有新数据时会立即推送给客户端。
- 用
newDataAvailable标记是否有新的串口数据,SSE连接建立后,服务器会持续检查这个标记,有新数据就推送给客户端。 - 前端通过
EventSourceAPI建立SSE连接,自动接收服务器推送的数据并更新页面。
额外注意事项
- 如果你的串口数据结束符不是
\n,可以根据实际情况修改readUart()中的判断条件(比如\r或者自定义的结束字符)。 - 确保ESP32的串口波特率和外部设备一致(当前代码是115200)。
- 如果串口数据量很大,可以考虑增加缓冲区溢出处理逻辑,避免数据丢失。
内容的提问来源于stack exchange,提问作者Tea
相关产品推荐
相关产品推荐

