arduino,使用 SD 配置文件中的数据设置以太网和网络

arduino, setup ethernet & network using data from SD config file

我尝试在我的草图中添加一种动态方式来从配置文件 (config.txt) 设置以太网信息 (mac、ip、网关、子网)。所以 运行 一个网络服务器并从 sd 卡提供 htm 文件,用户可以进入设置页面,用这些信息填写表格,当发布时,网络服务器解析 http 表格并保存(更新)config.txt文件。在该系统重新启动后,为了使用新设置开始(通过读取 config.txt 文件)

除了通过读取 config.txt 文件获取参数外,我已经成功创建了所有部分(sd、以太网、网络服务器、网络客户端、从发布的表单数据创建配置文件)。

我可以逐行读取配置,我可以将行拆分为参数和值,现在我需要用读取的数据填充一些字节变量。我可以(经过一个月的 google 搜索)将 IP(十进制值)读取到字节数组。我堆栈读取 MAC ADDRESS 十六进制到字节数组。配置文件包含:

mac=8f:2c:2b:19:e0:b7;
ip=192.168.1.200;
netmask=255.255.255.0;
gateway=192.168.1.254;
dns=8.8.8.8;
posturl=192.168.1.157;
postport=8080;
postscript=/itherm/update.php;
interval=60000;

我用来阅读的代码是:

byte myMAC[6];
byte myIP[4];

  File fset;
  fset = SD.open("config.txt");
  if (fset){
    char ff[40];
    while (fset.available()>1){
      bool eol=false;
      for (int i=0; !eol;i++){
        ff[i]=fset.read();
        if (ff[i]=='\n'){
           eol=true;
        }
      }
      String par="";
      bool DONE=false;
      for (int i=0; !DONE;i++){
        par+=ff[i];
        if (ff[i]== '='){DONE=true;}
      }
      String pval="";
      DONE=false;
//------------------------

      if (par=="ip=" ){
        int x=0;
        while(!DONE){
          for(int i=3;i<=i+21;i++){
            if(ff[i]=='.'){
              myIP[x]=pval.toInt();
              x++;
              i++;
              pval="";
            }
            else if(ff[i]==';' || i>20){
              myIP[x]=pval.toInt();
              DONE=true;
              break;
            }
            pval+=ff[i];
          }
        }
      }

    } //while (fset.available()>1)
  } //if (fset)

如有任何帮助,我将不胜感激。请不要简单地使用 Serial.print() 来回答。我发现了数百条建议,但 none 可以正常读取所有参数(十进制、十六进制、字符串)。经过一个月的努力和搜索,我想知道为什么社区中不存在如此必要和有用的示例,完全可用!!

此致

好的,这里有一套完整的例程来做你想做的事 - 我认为你误解了 char 数组与单个 char[0] 的概念。这些例程已记录在案并且不言自明。我建议不要用 ; 结束行但是使用 '\n' 在您的示例中仍然存在(您也看不到新行终止符)要获得 mac 地址,我需要三行:

  if (strncmp(cfgLine, "mac=", 4) == 0) {
    strcpy (macAddr, cfgLine + 4);
  }

第一行比较前 4 个字符,如果为 0(表示匹配) 第二行将lineBuffer中的第五个到最后一个字符复制到目标数组中,实际上可以用作函数的参数。
文件结构应该没有;正如您必须解析的那样;和\n

mac=8f:2c:2b:19:e0:b7
ip=192.168.1.200
....
postport=8080

要将 char 数组转换为 int,我们使用 atoi(),将单个 char[0] 转换为单个数字,我们使用 int singleDigit = char[0]-48;

const char configurationFilePath [] = "/someconfig.txt";
char cfgLine[128] = {'[=12=]'};  // this is a global temp char array to hold the read lines (lenght= chars longest line +1)
char numBuffer[16] = {'[=12=]'};  // this is a global temo char array to help to convert char to number

char macAddr [18] =  {'[=12=]'};  // this is a global char array to hold the mac address
char ipAddr [16] =  {'[=12=]'};  // this is a global char array to hold the IP address - max xxx.xxx.xxx.xxx
int postport=0;
// .... you can easyly implement for all other data you want to store/retrieve

// Counts the lines of a file 
uint16_t countLines() {
  uint16_t currentLineCount = 0;
  File cfgFile = SD.open(configurationFilePath, "r");
  if (!cfgFile) {
    Serial.println(F("Config file open failed on read"));
  } else {
    while (cfgFile.available()) {
      /** Lets read line by line from the file */
      if (cfgFile.read() == '\n') currentLineCount ++; // Lines are delimited by '\n'
    }
    cfgFile.close();
  }
  return currentLineCount;
}

//Load the config file from SD/SPIFFS/LittleFS
bool loadConfigFile() {
  uint16_t lineCounter = countLines();
  if (lineCounter <= 0)  {
    Serial.print(F("No config data stored in file ")); Serial.println(configurationFilePath);
    return false;
  }
  else {
    File cfgFile = SD.open(configurationFilePath, "r");
    while (cfgFile.available()) {
      strcpy (cfgLine, (cfgFile.readStringUntil('\n').c_str()));  // normaly you use new line, we copy one line at a time
//      Serial.println(cfgLine); /** Printing for debuging purpose */
      while (cfgLine[0] != '[=12=]') { /* Block refilling of cfgLine till processed */
        loadSingleCfgLine();
      }
    }
    cfgFile.close();
    Serial.println(F("[Success] Loaded config !"));
    return true;
  }
}
//Load the data of a single line into a char array
void loadSingleCfgLine() {
  if (strncmp(cfgLine, "mac=", 4) == 0) {
    strcpy (macAddr, cfgLine + 4);
  }
  if (strncmp(cfgLine, "ip=", 3) == 0) {
    strcpy (ipAddr, cfgLine + 3);
  }
  if (strncmp(cfgLine, "postport=", 9) == 0) {
    strcpy (numBuffer, cfgLine + 9);
    postport = atoi(numBuffer); // One extra step to convert to int
  }

// ... easy to implement for all other data
}

我把例程分成小的独立函数,所以它很容易适应不同的用途。很抱歉没有深入研究您的代码,因为它很难理解并且不清楚您想要做什么。
作为额外的好处,我们不使用字符串 class。这些字符串倾向于碎片化堆 - 导致 resets/crashes 而全局字符数组被编译为闪存并且不显示此行为。