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

基于A9G与ESP8266 D1 Mini实现全自动GPS追踪器的代码修改方案

A9G+ESP8266 全自动GPS追踪代码修改方案

核心修改点

  • 上电自动完成GSM、GPS初始化,无需手动输入指令
  • 增加定位数据有效性校验,过滤空值、未定位成功的无效数据
  • 采用非阻塞计时实现20分钟固定间隔发送,避免delay()卡死串口通信逻辑
  • 首次获取有效定位后自动发送第一条短信,之后循环按周期发送直到断电
  • 保留原有手动调试指令功能,不影响串口调试

具体修改说明

  1. 新增全局变量
    增加目标手机号宏定义、非阻塞计时变量、运行状态标记,替换原来硬编码的手机号、固定位置截取字符串的脆弱逻辑。
  2. setup阶段自动初始化
    移除原有手动操作提示的冗余打印,增加A9G模块上电就绪等待时间,模块启动后自动开启GPS功能,完成短信模式配置。
  3. 优化定位数据解析逻辑
    原代码固定从第33位截取字符串的逻辑容错性极差,不同固件版本返回长度差异会直接导致取数错误。修改后先匹配A9G定位返回的固定前缀+LOCATION:,再提取经纬度字段,同时校验字段长度、排除未定位时返回的空值/全0值。
  4. 非阻塞周期发送逻辑
    用ESP8266内置的millis()函数做时间差计算,不会阻塞串口数据接收:
    • 首次拿到有效定位立刻触发短信发送,标记首条发送状态,记录发送时间戳
    • 之后每轮循环判断当前时间与上次发送时间的差值,达到20分钟(1200000毫秒)就触发发送,更新时间戳
  5. 优化串口接收逻辑
    缩短串口超时时间,避免readString()长时间等待阻塞主循环,每次发送短信后清空接收缓存,避免模块返回的指令应答干扰定位解析。

修改后完整代码

// GPS tracker with AI Thinker A9G module and ESP8266 D1 Mini
#include <SoftwareSerial.h>

#define rxPin D7
#define txPin D8
#define TARGET_PHONE "+86xxxxxxxxxxx" // 替换为接收短信的手机号,国内号码加+86前缀
#define SEND_INTERVAL 1200000         // 发送间隔,20分钟=1200000毫秒
SoftwareSerial A9modem(rxPin, txPin);

String incomingData;
String gpsData = "";
unsigned long lastSendTime = 0;
bool firstSendDone = false;
bool gpsStarted = false;

void setup()
{
  Serial.begin(115200);
  A9modem.begin(115200);
  A9modem.setTimeout(500); // 缩短串口超时,避免阻塞
  
  Serial.println("Auto GPS Tracker Start");
  // 等待A9G模块上电就绪
  delay(3000);
  
  // 配置短信文本模式
  A9modem.println("AT+CMGF=1\r");
  delay(500);
  A9modem.println("AT+CNMI=2,2,0,0,0\r");
  delay(500);
  
  // 自动启动GPS
  StartGPS();
  gpsStarted = true;
}

void loop()
{
  // 持续接收模块返回数据
  ReceiveMessage();
  
  // 解析有效定位数据
  if (incomingData.startsWith("+LOCATION:")) {
    // 提取经纬度部分,跳过返回头
    int locStartIndex = incomingData.indexOf(":") + 2;
    if (locStartIndex < incomingData.length()) {
      String tempLoc = incomingData.substring(locStartIndex);
      tempLoc.trim();
      // 校验定位有效性:长度足够、不是无效的0,0返回
      if (tempLoc.length() >= 15 && tempLoc != "0.000000,0.000000") {
        gpsData = tempLoc;
        Serial.print("Valid Location Got: ");
        Serial.println(gpsData);
      }
    }
  }

  // 自动发送逻辑
  if (gpsData.length() > 0) {
    // 首次有效定位立刻发送
    if (!firstSendDone) {
      SendMessage();
      firstSendDone = true;
      lastSendTime = millis();
      Serial.println("First location SMS sent");
    } 
    // 达到间隔周期发送
    else if (millis() - lastSendTime >= SEND_INTERVAL) {
      SendMessage();
      lastSendTime = millis();
      Serial.println("Periodic location SMS sent");
    }
  }

  // 保留原有手动调试功能
  if (Serial.available() > 0) {
    switch(Serial.read())
    {
      case 's':
        SendMessage();
        break;
      case 'r':
        ReceiveMessage();
        break;
      case 'c':
        MakeCall();
        break;
      case 'h':
        HangupCall();
        break;
      case 'l':
        ReadLocation();
        break;
      case 'd':
        DisconnectGps();
        break;  
    }
  }
  // 定期请求定位数据,每2秒读一次
  static unsigned long lastLocReq = 0;
  if (millis() - lastLocReq >= 2000 && gpsStarted) {
    ReadLocation();
    lastLocReq = millis();
  }
}

void ReceiveMessage()
{
  incomingData = "";
  if (A9modem.available() > 0)
  {
    incomingData = A9modem.readString();
    Serial.print(incomingData); 
  }
}

void SendMessage()
{
  if (gpsData.length() == 0) {
    Serial.println("No valid location, skip send");
    return;
  }
  A9modem.println("AT+CMGF=1");
  delay(1000);
  A9modem.print("AT+CMGS=\"");
  A9modem.print(TARGET_PHONE);
  A9modem.println("\"\r");
  delay(1000);
  String sms = "http://maps.google.com/maps?q=" + gpsData;
  A9modem.println(sms);
  delay(100);
  A9modem.println((char)26); // CTRL+Z结束短信输入
  delay(1000);
  // 清空接收缓存避免返回数据干扰解析
  while(A9modem.available()) A9modem.read();
}

void MakeCall()
{
  A9modem.print("ATD+");
  A9modem.print(TARGET_PHONE);
  A9modem.println(";");
  Serial.println("Calling");
  delay(1000);
}

void HangupCall()
{
  A9modem.println("ATH");
  Serial.println("Hangup Call");
  delay(1000);
}

void DisconnectGps()
{
  A9modem.println("AT+GPS=0");
  Serial.println("GPS Disconnected");
  gpsStarted = false;
  delay(1000);
}

void StartGPS()
{
  A9modem.println("AT+GPS=1");
  Serial.println("GPS Started, waiting for satellite fix...");
  delay(2000);
}

void ReadLocation()
{
  A9modem.println("AT+LOCATION=2");
}

注意事项

  • 冷启动首次搜星需要在室外开阔环境进行,室内、遮挡严重的区域可能数分钟都无法获取有效定位,属于正常现象
  • 代码中20分钟间隔可通过修改SEND_INTERVAL宏定义调整,单位为毫秒
  • 若使用物联网卡,需确认卡已开通短信权限,且有足够余额
  • A9G模块供电需保证5V/2A以上,供电不足会导致搜网、搜星失败甚至模块反复重启

内容的提问来源于stack exchange,提问作者Vetinari

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.29 05:45:38