You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.28 05:03:15