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

Arduino Leonardo运行数轮循环后卡顿问题:原因及解决方法

嘿,看起来你的GPS追踪器遇到了典型的串口资源冲突或者阻塞问题!前几轮正常之后卡顿,大概率是SoftwareSerial的局限性或者代码里的阻塞操作搞的鬼,我给你拆解几个可能的原因和解决办法:

可能的原因&解决办法

1. SoftwareSerial拖垮了系统资源

SoftwareSerial是用模拟IO实现的串口,本质上靠CPU不断轮询引脚,而且不能同时收发,还会临时禁用其他中断——这就麻烦了:当你的HardwareSerial(GPS)在输出数据时,SoftwareSerial(GPRS)的操作可能会打断它,或者反过来导致数据堆积,最后系统因为处理不过来直接卡死。

解决办法:

  • 如果你的板子有多余的硬件串口(比如Arduino Mega有3个额外的HardwareSerial),直接把GPRS接到硬件串口上,彻底摆脱SoftwareSerial的限制。
  • 必须用SoftwareSerial的话,绝对不要在GPRS操作时用delay(),改用millis()做非阻塞计时,同时尽量把波特率降到9600(高波特率下SoftwareSerial的误差极大,容易丢数据)。

2. 串口缓冲区溢出导致崩溃

GPS模块会不断输出NMEA语句,GPRS模块也会返回AT指令响应,如果你的代码没有及时读取这些数据,串口缓冲区会被填满,最后溢出导致系统卡死——前几轮数据少还能撑住,多了就崩了。

解决办法:

  • 在loop()里优先处理串口数据,不管你用不用,都要及时读取:
// 处理GPS数据,避免缓冲区溢出
while(gpsSerial.available()) {
  gps.processData(); // 或者直接用read()清空缓冲区
}
// 处理GPRS响应,避免堆积
while(gprsSerial.available()) {
  char c = gprsSerial.read();
  // 可以打印出来调试,或者直接忽略
}
  • 绝对不要在循环里创建对象或者分配大量内存,比如把所有变量定义在全局或者setup()里,避免内存泄漏。

3. 供电不足导致模块罢工

GPS和GPRS都是耗电大户,尤其是GPRS发送数据时瞬间电流能到几百毫安。前几次发送可能电源还能扛住,之后电压被拉低,模块要么重启要么直接罢工,系统自然就卡顿了。

解决办法:

  • 换个功率足够的电源:比如5V/2A以上的适配器,或者用带升压模块的锂电池(比如3.7V锂电池升到5V,输出电流至少1A)。
  • 在模块的电源引脚旁加滤波电容:1000uF的电解电容+0.1uF的陶瓷电容,能缓解电压波动带来的不稳定。

4. 阻塞式操作卡死了系统

如果你的代码里用了delay(INTERVAL)或者GPRS的阻塞式发送函数(比如sendData()一直等响应),系统会在这段时间里完全停住,串口数据没人处理,堆积多了就崩了。

解决办法:

  • 把所有delay()换成millis()的非阻塞计时,像这样:
unsigned long previousMillis = 0;
const long interval = INTERVAL;

void loop() {
  unsigned long currentMillis = millis();
  if(currentMillis - previousMillis >= interval) {
    previousMillis = currentMillis;
    // 这里执行发送数据的操作
  }
  // 其余时间处理串口数据
}
  • 调用GPRS发送函数时,不要一直等待响应,先检查模块是否就绪,或者设置超时时间,避免无限阻塞。
优化后的代码示例

这里给你改了个非阻塞的版本,你可以参考:

#include <GPRS_Shield_Arduino.h>
#include <TroykaGPS.h>
#include <SoftwareSerial.h>

#define IMEI "你的IMEI号"
#define INTERVAL 5000 // 发送间隔(毫秒)
#define GPRS_APN "你的运营商APN"
#define GPRS_USER "" // 大部分APN不需要用户名密码
#define GPRS_PWD ""

// 硬件串口接GPS(Mega用Serial1,Uno如果用Serial要注意和USB串口冲突)
HardwareSerial gpsSerial(1);
TroykaGPS gps(gpsSerial);

// SoftwareSerial接GPRS,选支持中断的引脚(Uno的2、3脚)
SoftwareSerial gprsSerial(2, 3);
GPRS gprs(gprsSerial);

unsigned long lastSendTime = 0;

void setup() {
  Serial.begin(9600);
  gpsSerial.begin(9600);
  gprsSerial.begin(9600);

  // 等待GPS定位
  Serial.println("等待GPS定位...");
  while(!gps.waitForFix(10000)) {
    Serial.println("未定位,继续等待...");
  }
  Serial.println("GPS定位成功!");

  // 连接GPRS
  Serial.println("连接GPRS...");
  if(gprs.attachGPRS(GPRS_APN, GPRS_USER, GPRS_PWD)) {
    Serial.println("GPRS连接成功!");
  } else {
    Serial.println("GPRS连接失败,请检查APN设置!");
  }
}

void loop() {
  unsigned long now = millis();

  // 优先处理串口数据,避免缓冲区溢出
  while(gpsSerial.available()) {
    gps.processData();
  }
  while(gprsSerial.available()) {
    char c = gprsSerial.read();
    Serial.print(c); // 打印GPRS响应方便调试
  }

  // 非阻塞式发送数据
  if(now - lastSendTime >= INTERVAL) {
    lastSendTime = now;

    if(gps.isFixed()) {
      // 组装GPS数据
      String gpsData = String(gps.getLatitude(), 6) 
                      + "," + String(gps.getLongitude(), 6)
                      + "," + String(gps.getAltitude());
      Serial.println("准备发送数据: " + gpsData);

      // 发送到服务器(替换成你的服务器IP和端口)
      if(gprs.sendTCP("192.168.1.100", 8080, gpsData)) {
        Serial.println("数据发送成功!");
      } else {
        Serial.println("发送失败,稍后重试...");
      }
    } else {
      Serial.println("GPS未定位,跳过发送");
    }
  }
}

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.25 07:38:14