ESP8266+Arduino调用Telegram API时响应截断问题排查
ESP8266通过SoftwareSerial连接Arduino Uno向Telegram API发送请求时响应截断问题
我用SoftwareSerial将ESP8266与Arduino Uno连接,向Telegram API发送GET请求,AT指令打印信息正常,但服务器返回的响应始终存在截断情况。
原代码
#include <SoftwareSerial.h> SoftwareSerial mySerial(8, 9); #define WIFI_SERIAL mySerial String command(const char *toSend, unsigned com_delay, unsigned milliseconds) { String result; Serial.print("Sending: "); Serial.println(toSend); WIFI_SERIAL.println(toSend); unsigned long startTime = millis(); Serial.print("Received: "); delay(com_delay); while (millis() - startTime - com_delay < milliseconds) { if (WIFI_SERIAL.available()) { delay(1); char c = WIFI_SERIAL.read(); Serial.write(c); result += c; // append to the result string } } Serial.println(); // new line after timeout. return result; } void setup() { Serial.begin(9600); while (!Serial); Serial.print("Serial init OK\n"); WIFI_SERIAL.begin(9600); char concom[] = "AT+CWJAP_DEF=\"---\",\"---\""; char sendcom[] = "AT+CIPSTART=\"TCP\",\"api.telegram.org\",443"; char api[] = "GET /botxxxxxxxxxxxxxxxxxxxx/ HTTP/1.1\nHost: api.telegram.org\nAccept: application/json\nCache-Control: no-cache\n\n"; //command("AT+CWMODE=1", 10000, 100); command(concom, 7000, 500); command(sendcom, 10000, 500); command("AT+CIPSEND=139", 3000, 500); Serial.println("+"+command(api, 40000, 15000)); } void loop() { while(WIFI_SERIAL.available()) { char line = WIFI_SERIAL.read(); // read one char at a time delay(1); // prevent freezing Serial.print(line); // if (line == '\0') continue; // terminate the `while` when end of the data } }
服务器返回内容
Serial init OK 00:02:08.438 -> Sending: AT+CWJAP_DEF="---","---" 00:02:08.469 -> Received: T+CWJAP_DEF="---","----" 00:02:15.526 -> busy s... 00:02:15.531 -> 00:02:15.531 -> Recv 1 00:02:15.959 -> Sending: AT+CIPSTART="TCP","api.telegram.org",443 00:02:16.026 -> Received: 00:02:26.021 -> Sending: AT+CIPSEND=139 00:02:26.082 -> Received: AT+CIPSTART="TCP","api.telegram.org",443 00:02:29.090 -> CONNECT 00:02:29.090 -> 00:02:29.090 -> OK 00:02:29.090 -> AT+CI 00:02:29.551 -> Sending: GET /botxxxxxxxxxxxxxx/ HTTP/1.1 00:02:29.613 -> Host: api.telegram.org 00:02:29.646 -> Accept: application/json 00:02:29.679 -> Cache-Control: no-cache 00:02:29.679 -> 00:02:29.679 -> 00:02:29.779 -> Received: 00:03:09.792 -> + 00:03:09.853 -> 00:03:09.853 -> busy s... 00:03:09.853 -> 00:03:09.853 -> Recv 139 bytes 00:03:09.853 -> 00:03:09.853 -> SEND OK 00:03:09.858 -> 00:03:09.858 -> +IPD,595:HTTP/1.1 4 // <---- HERE IS INCOMPLETED ANSWER
问题原因与解决方法
核心问题点
- HTTPS连接错误:Telegram API的443端口是HTTPS服务,原代码用
TCP连接,属于明文请求,服务器返回的响应会异常,甚至被截断。 - SoftwareSerial性能限制:软串口是模拟实现的,9600波特率下缓存有限,处理595字节的响应时容易丢包,加上代码中
delay(1)的额外阻塞,导致无法及时读取所有数据。 - 超时逻辑不合理:
command函数中先执行固定时长的delay(com_delay),这段时间内ESP8266返回的数据可能因缓存溢出丢失。 - 请求长度计算错误:
AT+CIPSEND=139的长度参数可能与实际HTTP请求长度不符,导致发送不完整或响应异常。
修正后的代码
#include <SoftwareSerial.h> SoftwareSerial mySerial(8, 9); #define WIFI_SERIAL mySerial String command(const char *toSend, unsigned long timeoutMs) { String result; Serial.print("Sending: "); Serial.println(toSend); WIFI_SERIAL.println(toSend); unsigned long startTime = millis(); Serial.print("Received: "); // 实时读取串口数据,直到超时 while (millis() - startTime < timeoutMs) { while (WIFI_SERIAL.available()) { char c = WIFI_SERIAL.read(); Serial.write(c); result += c; } } Serial.println(); return result; } void setup() { Serial.begin(115200); // 提高硬件串口波特率,加快调试输出 while (!Serial); Serial.println("Serial init OK"); WIFI_SERIAL.begin(115200); // 提高软串口波特率,减少传输延迟 char concom[] = "AT+CWJAP_DEF=\"你的WiFi名称\",\"你的WiFi密码\""; // 改用SSL连接HTTPS服务 char sendcom[] = "AT+CIPSTART=\"SSL\",\"api.telegram.org\",443"; // 构造标准HTTP请求,用\r\n换行符符合协议规范 String apiRequest = "GET /botxxxxxxxxxxxxxxxxxxxx/getMe HTTP/1.1\r\nHost: api.telegram.org\r\nAccept: application/json\r\nCache-Control: no-cache\r\n\r\n"; // 连接WiFi,超时10秒 command(concom, 10000); // 建立SSL连接,超时10秒 command(sendcom, 10000); // 自动计算请求长度,避免手动输入错误 String sendLenCmd = "AT+CIPSEND=" + String(apiRequest.length()); command(sendLenCmd.c_str(), 3000); // 发送API请求,超时20秒 Serial.println("+"+command(apiRequest.c_str(), 20000)); } void loop() { // 实时读取ESP8266返回的剩余数据 while(WIFI_SERIAL.available()) { char c = WIFI_SERIAL.read(); Serial.print(c); } }
额外优化建议
- 如果软串口仍存在丢包问题,建议改用Arduino Uno的硬件串口(引脚0/1)连接ESP8266,注意上传代码时需断开ESP8266的TX/RX引脚,避免串口冲突。
- 可以开启ESP8266的AT指令长响应模式,使用
AT+CIPRECVMODE=1设置为被动接收,通过AT+CIPRECVDATA主动读取响应数据,减少软串口的实时压力。
内容的提问来源于stack exchange,提问作者Nikita0607
相关产品推荐
相关产品推荐

