SIM808搭配Arduino请求OpenWeatherMap时AT+HTTPREAD返回JSON不完整求解
问题1:AT+HTTPREAD返回JSON不完整的修复方案
- 扩大SoftwareSerial接收缓冲区:SIM808返回的JSON长度通常在200字节以上,而SoftwareSerial默认接收缓冲区仅64字节,超出部分会直接丢失。在引入SoftwareSerial头文件前添加宏定义修改缓冲区大小:
#define _SS_MAX_RX_BUFF 512 #include <SoftwareSerial.h> SoftwareSerial GSM808(7,8);
- 重写串口数据读取函数:原有读取逻辑只要当前串口缓冲区无数据就直接退出,而SIM808会分批返回数据,传输延迟会导致提前终止读取。修改为带超时的读取逻辑:
void printSerialData(char* recvBuf = NULL, int bufLen = 0) { int index = 0; unsigned long lastRecvTime = millis(); while(millis() - lastRecvTime < 200) // 200ms无新数据则认为传输完成 { if(GSM808.available()) { char c = GSM808.read(); Serial.write(c); if(recvBuf != NULL && index < bufLen -1) { recvBuf[index++] = c; } lastRecvTime = millis(); } } if(recvBuf != NULL) recvBuf[index] = '\0'; delay(100); }
- 调整HTTP请求等待逻辑:
AT+HTTPACTION=0发送后不要固定等待1秒,要等待模块返回+HTTPACTION:0,200,XXX响应,其中XXX为返回内容的总长度,确认内容完全下载到模块本地后再执行读取:
GSM808.println("AT+HTTPACTION=0"); char resp[256] = {0}; printSerialData(resp, 256); // 提取返回内容长度 int contentLen = 0; char* p = strstr(resp, "+HTTPACTION:0,200,"); if(p != NULL) { contentLen = atoi(p + 17); } // 按实际长度读取全部内容 char readCmd[32] = {0}; sprintf(readCmd, "AT+HTTPREAD=0,%d", contentLen); GSM808.println(readCmd); char jsonBuf[512] = {0}; printSerialData(jsonBuf, 512); // 后续从jsonBuf中提取JSON有效内容即可
- 额外优化:原有逻辑将整个请求流程放在loop中会高频重复请求,建议调整为仅在setup执行一次,或添加10分钟以上的请求间隔,避免触发OpenWeatherMap的接口频率限制。
问题2:JSON字段提取方案
使用专为嵌入式设备开发的ArduinoJson库完成解析,资源占用低,适配Arduino平台:
- 先从读取到的完整返回内容中截取出纯JSON字符串,去掉
+HTTPREAD开头的响应头和结尾的OK标识 - 调用ArduinoJson库解析,示例代码如下:
#include <ArduinoJson.h> void parseWeatherJson(char* jsonStr) { StaticJsonDocument<512> doc; DeserializationError error = deserializeJson(doc, jsonStr); if(error) return; // 提取所需字段示例 float temp = doc["main"]["temp"]; // 温度 int humidity = doc["main"]["humidity"]; // 湿度 const char* weather = doc["weather"][0]["main"]; // 天气状态 // 后续可自行保存到变量中使用 }
内容的提问来源于stack exchange,提问作者Severin Baumgartner
相关产品推荐
相关产品推荐

