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

如何在AtMega2560中解析ESP模块发来的逗号分隔串口数据

问题描述

我用Arduino开发的内置WiFi的AtMega2560已基本正常工作。ESP模块从ThingSpeak获取各温度传感器读数,将其以逗号分隔的字符串通过串口发送给AtMega2560,现在需要解析这个字符串,把每个读数分配给单独的变量。以下是ESP模块、AtMega2560的代码及输出示例,求解决方案。

ESP模块代码

#include <SPI.h>
#include <Wire.h>
#include "ThingSpeak.h"
#include <ESP8266WiFi.h>
const char ssid[] = "Beep";  // 你的网络SSID(名称)
const char pass[] = "Bap";   // 你的网络密码

WiFiClient  client;

//---------通道详情---------//
unsigned long counterChannelNumber1 = 0000000;            // 通道ID(当前)
unsigned long counterChannelNumber2 = 0000000;            // 通道ID(当前)
unsigned long counterChannelNumber3 = 0000000;            // 通道ID(当前)
const char * myCounterReadAPIKey1 = "REPLACEME"; // 读取API密钥(需要修改)
const char * myCounterReadAPIKey2 = "REPLACEME"; // 读取API密钥(需要修改)
const char * myCounterReadAPIKey3 = "REPLACEME"; // 读取API密钥(需要修改)
const int FieldNumber1 = 1;  // 要读取的字段
const int FieldNumber2 = 2;  // 要读取的字段
const int FieldNumber3 = 3;  // 要读取的字段
const int FieldNumber4 = 4;  // 要读取的字段
const int FieldNumber5 = 5;  // 要读取的字段
const int FieldNumber6 = 6;  // 要读取的字段
const int FieldNumber7 = 7;  // 要读取的字段
const int FieldNumber8 = 8;  // 要读取的字段
//-------------------------------//
 
void setup()   {
  Serial.begin(115200);
  WiFi.mode(WIFI_STA);
  ThingSpeak.begin(client);
  Serial.println("[ON]");
}
 
void loop() {
  //----------------- 网络连接 -----------------//
  if (WiFi.status() != WL_CONNECTED)
  {
    Serial.print("Connecting to ");
    Serial.print(ssid);
    Serial.println(" ....");
    while (WiFi.status() != WL_CONNECTED)
    {
      WiFi.begin(ssid, pass);
      delay(5000);
    }
    Serial.println("Connected to Wi-Fi Succesfully.");
  }

  //----------------- 房间1 -----------------//  
  long Room1 = ThingSpeak.readLongField(counterChannelNumber1, FieldNumber1, myCounterReadAPIKey1);
  int statusCode = ThingSpeak.getLastReadStatus();
  if (statusCode != 200)
  {
    Serial.println("Unable to read channel / No internet connection");
  }
  //----------------- 房间1结束 -----------------//  

  //----------------- 房间2 -----------------//  
  long Room2 = ThingSpeak.readLongField(counterChannelNumber1, FieldNumber2, myCounterReadAPIKey1);
  statusCode = ThingSpeak.getLastReadStatus();
  if (statusCode != 200)
  {
    Serial.println("Unable to read channel / No internet connection");
  }
  //----------------- 房间2结束 -----------------//  

  //----------------- 房间3 -----------------//  
  long Room3 = ThingSpeak.readLongField(counterChannelNumber1, FieldNumber3, myCounterReadAPIKey1);
  statusCode = ThingSpeak.getLastReadStatus();
  if (statusCode != 200)
  {
    Serial.println("Unable to read channel / No internet connection");
  }
  //----------------- 房间3结束 -----------------//  

  //----------------- 房间4 -----------------//  
  long Room4 = ThingSpeak.readLongField(counterChannelNumber1, FieldNumber4, myCounterReadAPIKey1);
  statusCode = ThingSpeak.getLastReadStatus();
  if (statusCode != 200)
  {
    Serial.println("Unable to read channel / No internet connection");
  }
  //----------------- 房间4结束 -----------------//  

  //----------------- 房间5 -----------------//  
  long Room5 = ThingSpeak.readLongField(counterChannelNumber1, FieldNumber5, myCounterReadAPIKey1);
  statusCode = ThingSpeak.getLastReadStatus();
  if (statusCode != 200)
  {
    Serial.println("Unable to read channel / No internet connection");
  }
  //----------------- 房间5结束 -----------------//  

  //----------------- 房间6 -----------------//  
  long Room6 = ThingSpeak.readLongField(counterChannelNumber1, FieldNumber6, myCounterReadAPIKey1);
  statusCode = ThingSpeak.getLastReadStatus();
  if (statusCode != 200)
  {
    Serial.println("Unable to read channel / No internet connection");
  }
  //----------------- 房间6结束 -----------------//  

  //----------------- 房间7 -----------------//  
  long Room7 = ThingSpeak.readLongField(counterChannelNumber1, FieldNumber7, myCounterReadAPIKey1);
  statusCode = ThingSpeak.getLastReadStatus();
  if (statusCode != 200)
  {
    Serial.println("Unable to read channel / No internet connection");
  }
  //----------------- 房间7结束 -----------------// 
   
  //----------------- 房间8 -----------------//  
  long Room8 = ThingSpeak.readLongField(counterChannelNumber1, FieldNumber8, myCounterReadAPIKey1);
  statusCode = ThingSpeak.getLastReadStatus();
  if (statusCode != 200)
  {
    Serial.println("Unable to read channel / No internet connection");
  }
  //----------------- 房间8结束 -----------------//  
  Serial.print(Room1);
  Serial.print(",");
  Serial.print(Room2);
  Serial.print(",");
  Serial.print(Room3);
  Serial.print(",");
  Serial.print(Room4);
  Serial.print(",");
  Serial.print(Room5);
  Serial.print(",");
  Serial.print(Room6);
  Serial.print(",");
  Serial.print(Room7);
  Serial.print(",");
  Serial.print(Room8);
  Serial.print(",\n");
  delay(10000);
}

AtMega2560代码

char *strings[8]; // strtok()后存储各片段的指针数组
char *ptr = NULL;
float room1t, room2t, room3t, room4t, room5t, room6t, room7t, room8t;
String inString;
char raw;
void setup()
{
   Serial.begin(115200);
   Serial3.begin(115200);
}

void loop()
{
   while (Serial3.available()) {
   raw = Serial3.read();
   Serial.write(raw);
   inString += raw;
   } 
}

输出示例

Connected to Wi-Fi Succesfully.

23,23,22,23,23,23,22,23,

23,23,22,23,23,23,22,23,

23,23,22,23,23,23,22,23,

23,23,22,23,23,23,22,23,
解决方案

1. 优化ESP模块的输出格式

当前ESP输出的字符串末尾多了一个逗号,会导致解析时出现空值。修改ESP代码中最后的输出部分,去掉末尾多余的逗号,用换行符作为完整数据的结束标记:

// 替换原输出代码
Serial.print(Room1);
Serial.print(",");
Serial.print(Room2);
Serial.print(",");
Serial.print(Room3);
Serial.print(",");
Serial.print(Room4);
Serial.print(",");
Serial.print(Room5);
Serial.print(",");
Serial.print(Room6);
Serial.print(",");
Serial.print(Room7);
Serial.print(",");
Serial.println(Room8); // 用println输出最后一个值,自动添加换行符

修改后输出的每一行数据格式为 23,23,22,23,23,23,22,23,无多余逗号,方便后续解析。

2. 修改AtMega2560代码实现解析

在AtMega2560中检测换行符,当接收到完整一行数据时进行分割,将每个温度值转换为float类型并赋值给对应变量。修改后的代码如下:

float room1t, room2t, room3t, room4t, room5t, room6t, room7t, room8t;
String inString;

void setup()
{
  Serial.begin(115200);
  Serial3.begin(115200);
}

void loop()
{
  while (Serial3.available()) {
    char raw = Serial3.read();
    // 读到换行符时,开始解析整行数据
    if (raw == '\n') {
      Serial.println("\n===== 解析到的数据 =====");
      // 将String转换为char数组,供strtok分割使用
      char inputBuffer[100];
      inString.toCharArray(inputBuffer, sizeof(inputBuffer));
      
      // 第一次分割,逗号为分隔符
      char* token = strtok(inputBuffer, ",");
      int index = 0;
      
      // 循环分割所有字段
      while (token != NULL && index < 8) {
        // 将字符串转换为float并赋值给对应变量
        switch(index) {
          case 0: room1t = atof(token); break;
          case 1: room2t = atof(token); break;
          case 2: room3t = atof(token); break;
          case 3: room4t = atof(token); break;
          case 4: room5t = atof(token); break;
          case 5: room6t = atof(token); break;
          case 6: room7t = atof(token); break;
          case 7: room8t = atof(token); break;
        }
        // 输出解析结果
        Serial.print("房间");
        Serial.print(index+1);
        Serial.print("温度: ");
        Serial.println(atof(token));
        // 继续分割下一个字段
        token = strtok(NULL, ",");
        index++;
      }
      
      // 清空字符串,准备接收下一行数据
      inString = "";
    } else {
      // 过滤回车符,避免Windows风格换行干扰
      if (raw != '\r') {
        inString += raw;
        Serial.write(raw);
      }
    }
  }
}

代码说明

  • 以换行符作为完整数据的结束标记,确保每次解析的是一组完整的温度数据;
  • 使用strtok函数分割逗号分隔的字符串;
  • 通过atof函数将分割后的字符串转换为float类型温度值;
  • 用switch-case将每个值分配给对应房间的温度变量;
  • 解析完成后清空inString,准备接收下一组数据。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.12 19:40:33