Arduino MKR NB 1500收发数次MQTT消息后卡顿的原因排查
解决Arduino MKR NB 1500卡在serializeJson的问题
核心原因分析
MKR NB 1500的GSM模块在内存、带宽和串口缓冲区上的资源远不如MKR WiFi 1010,你的大JSON序列化+MQTT发送逻辑在资源受限的GSM环境下出现了阻塞或内存问题。
具体排查与修复步骤
1. 调整缓冲区大小适配大消息
- PubSubClient缓冲区:默认仅128字节,无法承载你的大JSON,初始化时手动扩容:
PubSubClient client(nbClient); client.setBufferSize(4096); // 适配12KB级别的JSON消息 - BufferingPrint缓冲区:当前32字节太小,会频繁触发底层GSM串口发送,大幅增加阻塞概率,调至256或512字节:
BufferingPrint bufferedClient{client, 512};
2. 优化内存使用避免碎片化
- 去掉冗余String转换:循环中把浮点数转String的操作会大量占用堆内存,还容易导致内存碎片化。直接让ArduinoJson处理浮点数,序列化时指定精度即可:
// 替换原循环中的String转换代码 obj["pwr"] = coffeeInfo[i].pwr; obj["t1"] = coffeeInfo[i].t1; obj["t2"] = coffeeInfo[i].t2; // 序列化时控制浮点数精度 serializeJson(coffeeDoc, bufferedClient, SerializeOption::Precision(1)); - 改用StaticJsonDocument:如果JSON结构和大小固定,用静态分配的文档替代DynamicJsonDocument,减少堆内存分配和碎片:
StaticJsonDocument<12288> coffeeDoc; // 替换DynamicJsonDocument
3. 添加调试追踪定位问题
在关键步骤插入串口打印,精准确认阻塞位置:
// 序列化前后加日志 Serial.println("[DEBUG] Starting JSON serialization..."); serializeJson(coffeeDoc, bufferedClient, SerializeOption::Precision(1)); Serial.println("[DEBUG] Serialization completed"); // 发送前检查GSM连接状态 if (!nb.isConnected()) { Serial.println("[DEBUG] Reconnecting GSM module..."); while (!nb.connect()) { delay(1000); Serial.print("."); } Serial.println("\n[DEBUG] GSM reconnected"); } // 打印剩余内存排查泄漏 Serial.print("[DEBUG] Free RAM: "); Serial.println(freeMemory()); // 需要包含<avr/pgmspace.h>
4. 完善MQTT发送容错逻辑
检查client.beginPublish的返回值,避免无意义的后续操作:
if (client.beginPublish("device/coffee", measureJson(coffeeDoc), false)) { // 执行序列化与发送 bufferedClient.flush(); client.endPublish(); } else { Serial.println("[ERROR] Failed to start MQTT publish"); // 可在此添加重试逻辑 }
修改后的完整代码片段
// 初始化时配置PubSubClient缓冲区 PubSubClient client(nbClient); client.setBufferSize(4096); // ...其他初始化代码... // 发送逻辑部分 if (!nb.isConnected()) { Serial.println("[DEBUG] Reconnecting GSM..."); while (!nb.connect()) { delay(1000); } } StaticJsonDocument<12288> coffeeDoc; coffeeDoc["device"]["id"] = boardID; JsonObject transaction = coffeeDoc.createNestedObject("transaction"); transaction["id"] = j; JsonArray transaction_data = transaction.createNestedArray("data"); for(int i = 0; i < total; i++){ JsonObject obj = transaction_data.createNestedObject(); obj["id"] = i; obj["ts"] = coffeeInfo[i].ts; obj["pwr"] = coffeeInfo[i].pwr; obj["t1"] = coffeeInfo[i].t1; obj["t2"] = coffeeInfo[i].t2; obj["extruder"] = coffeeInfo[i].extruder; obj["time"] = coffeeInfo[i].time; } Serial.println("[DEBUG] Starting MQTT publish..."); if (client.beginPublish("device/coffee", measureJson(coffeeDoc), false)) { BufferingPrint bufferedClient{client, 512}; Serial.println("[DEBUG] Serializing JSON..."); serializeJson(coffeeDoc, bufferedClient, SerializeOption::Precision(1)); Serial.println("[DEBUG] Serialization done"); bufferedClient.flush(); client.endPublish(); Serial.println("[DEBUG] Publish completed"); j++; } else { Serial.println("[ERROR] Publish initiation failed"); } coffeeDoc.clear();
内容的提问来源于stack exchange,提问作者AleG94
相关产品推荐
相关产品推荐

