Arduino拼接SIM7000E串口AT返回值到URL时打印异常
SIM7000E+Arduino GPS追踪器URL拼接异常排查
问题场景
使用SIM7000E模块搭配Arduino Nano制作GPS追踪器,目标是将多条AT指令的返回结果存入字符数组后拼接至URL末尾,向dweet.io上报定位数据,但实际打印的URL结果不符合预期。
涉及AT指令
AT+CGNSPWR=1:开启模块GPS功能AT+CGNSINF:输出NMEA格式定位数据
原有代码逻辑
- 引入SoftwareSerial库建立与SIM7000E的串口连接,初始化完成后依次发送上述两条AT指令
- 发送
AT+CGNSPWR=1后直接读取并清空当前串口缓冲区 - 发送
AT+CGNSINF后一次性读取当前串口可用的47个字节,分别存入ch~ch46共47个长度为2的单字符数组 - 将固定URL头、读取到的字符、URL尾拼接为完整的
AT+HTTPPARA指令后打印输出
输出对比
实际输出
AT+HTTPPARA="URL","http://dweet.io/dweet/for/mything?AT+CGNSPWR=1
OK
⸮⸮⸮⸮⸮⸮"
预期输出
AT+HTTPPARA="URL","http://dweet.io/dweet/for/mything?AT+CGNSPWR=1 OK AT+CGNSINF +CGNSINF: 1,1,20220702123007.000,-7.521564,113.05"
核心问题原因
- 缓冲区清空逻辑失效:发送
AT+CGNSPWR=1后用while(SIM7000E.available())读数据的写法,仅能读取执行到该行时缓冲区已收到的字节,不会等待后续返回内容,也无法彻底清空缓冲区残留的指令回显、OK返回等旧数据,导致后续读取CGNSINF数据时先读到残留旧内容。 - 串口读取逻辑错误:发送AT指令后未预留足够等待时间让模块返回完整数据,直接在
while(SIM7000E.available())循环中连续读取47个字节,此时模块还未将全部返回数据传入串口缓冲区,会读到空值/无效值(即输出中的乱码⸮);同时Arduino Nano的SoftwareSerial稳定性有限,无延时连续快速读字节极易出现丢数、乱码。 - 字符数组使用不规范:定义的ch~ch46数组长度为2,但初始化时仅存入1个读取到的字符,未手动补充C语言字符串必需的结束符
\0,调用strcat拼接时会读取数组外的随机内存值,直接导致乱码、数据错位。 - 代码逻辑顺序错误:
setup()函数内拼接打印URL后写了return 0;,直接终止setup执行流程,后续发送AT指令、读取返回的代码永远不会运行,根本无法获取CGNSINF的返回数据。 - AT指令发送格式错误:使用
SIM7000E.println()发送指令时会自动追加回车换行,代码中又手动在指令末尾添加\r\n,相当于给模块发送两次换行,会导致模块返回多余空行、识别指令异常。 - 指令间隔不合理:发送开启GPS的指令后未等待足够的搜星时间,立刻发送读取定位的指令,大概率无法拿到有效定位结果。
修正方案
- 修正AT指令发送格式:去掉
println()后手动添加的\r\n,避免重复换行。 - 封装通用的AT指令发送响应函数:发送指令后按设定超时时间等待模块返回,将所有返回内容存入统一缓存,读到超时或缓存满就停止,不要硬编码读取固定47字节,每读1个字节加1ms短延时,适配软串口稳定性。
- 废弃47个单字符数组的冗余写法,直接用长度足够的全局字符缓存存储模块返回内容,拼接URL前对缓存中的特殊字符做URL编码(如空格、逗号、正负号转义),避免URL格式错误。
- 删除
setup()中的return 0;语句,保证后续代码可正常执行。 - 增加指令执行校验:每条AT指令发送后,检测返回内容中是否包含
OK,确认指令执行成功后再发下一条;开启GPS后至少等待2-3秒(冷启动搜星需延长到10秒以上)再读取定位数据。 - 若19200波特率下软串口不稳定,可将SIM7000E串口波特率降到9600使用。
修正后示例代码
#include <SoftwareSerial.h> #include <string.h> SoftwareSerial SIM7000E(10, 11); //RX, TX const int SIM_BAUD = 9600; const char header[] = "AT+HTTPPARA=\"URL\",\"http://dweet.io/dweet/for/mything?"; const char trailer[] = "\"\r\n"; char respBuf[200] = {0}; // 存储模块返回内容的缓存 char urlBuf[300] = {0}; // 存储最终拼接的HTTP指令 // 通用AT指令发送+读取响应函数 void sendAT(const char* cmd, char* resp, int waitTime = 2000) { memset(resp, 0, 200); // 清空响应缓存 SIM7000E.println(cmd); long startTs = millis(); int idx = 0; while (millis() - startTs < waitTime) { while (SIM7000E.available()) { char c = SIM7000E.read(); if (idx < 198) { // 防止缓存溢出 resp[idx++] = c; } delay(1); // 软串口读加短延时防丢数 } } } void setup() { pinMode(11, OUTPUT); pinMode(10, INPUT); Serial.begin(9600); delay(1000); SIM7000E.begin(SIM_BAUD); delay(3000); // 等待模块开机完成 Serial.println("Initialising"); // 检测模块连接状态 sendAT("AT", respBuf, 1000); Serial.print("AT response: "); Serial.println(respBuf); if (strstr(respBuf, "OK") == NULL) { Serial.println("SIM module not responding, halt"); while (1); } // 开启GPS功能 sendAT("AT+CGNSPWR=1", respBuf, 3000); Serial.print("CGNSPWR response: "); Serial.println(respBuf); delay(5000); // 预留GPS搜星时间,冷启动可延长至10s以上 // 读取定位数据 sendAT("AT+CGNSINF", respBuf, 2000); Serial.print("CGNSINF response: "); Serial.println(respBuf); // 拼接最终HTTP指令 memset(urlBuf, 0, sizeof(urlBuf)); strcat(urlBuf, header); strcat(urlBuf, respBuf); strcat(urlBuf, trailer); Serial.println("Final HTTP AT command:"); Serial.println(urlBuf); // 后续可直接将urlBuf发送给模块执行HTTP请求 // SIM7000E.print(urlBuf); } void loop() { // 循环上报定位逻辑可在此实现 }
内容的提问来源于stack exchange,提问作者SockofSomething
相关产品推荐
相关产品推荐

