Сбой системы после использования sprintf

Мой Arduino вылетает после использования sprintf, чтобы уменьшить системную оперативную память, я пытаюсь перейти от строк к символу, и теперь это произошло. Цикл не работает должным образом, и он не собирается webrequest, потратил 2 дня, чтобы найти решение, пока ничего не работало. Мой проект состоит в том, чтобы отправить temp и humidly на мой сервер, я использовал строки, и после одного дня использования система очень медленно отправляла данные на сервер, тогда я понял, что виноваты укусы, а затем я перешел на char

char ventionoroff[6];

char Foggeronoroff[6] ;

char Exhuastonoroff[6] = "OFF";

char current[4];

char today[10];

bool running = false;
bool isFoggerRunning = false;
bool isExhaustFanRunning = false;





Time t;


void loop() {


  
 t = rtc.getTime();

  hum = dht.readHumidity();
  temp = dht.readTemperature();
  delay(1000);
  
  if (isnan(hum) || isnan(temp)) {
    Serial.println(F("Failed to read from DHT sensor!"));
    return;
  }
  val = digitalRead(powerStatus);


      byte MIN = t.hour;
      byte SEC = t.min;
     
  char timeStamp[20];
 snprintf(today, "%02d:%02d",  MIN, SEC);

   Serial.println(today);


if (millis() - lastConnectionTime > postingInterval) {
   Serial.println("reaching here2");
    httpRequest();
  }

  if (val)
  snprintf( current , "YES");
   
  else
 snprintf( current , "NO");
   
 
  if (running == false) {
    snprintf( Foggeronoroff , "WAIT");
   
  } else {
   snprintf( Foggeronoroff , "READY");
   
  }
  
    ventilationfan();
  






void httpRequest() {
Serial.println("shit reached here");
  client.stop();
  char data[10];
  const char phpScript[21]  = "";
  const char server[20]  =  ""; // также измените строку хоста в HttpRequest()

   char strt[6];
   char str[6];
  sprintf(strt, "te=%d", temp);
  strcpy(data, strt);
  strcat (data,"&ti=");
  strcat (data,today);
   strcat (data,"&mot=");
   strcat (data,ventionoroff);
   strcat (data,",");
   strcat (data,Foggeronoroff);
    strcat (data,",");
    strcat (data,current);
     strcat (data,"&mo=");
     strcat (data,Exhuastonoroff);
      sprintf(str, "&hum=%d",hum);
      strcat (data,str);
       
 Serial.println(data);
   int len = strlen(data);
  if (client.connect(server, 80)) {
    client.print("POST ");
    client.print(phpScript);
    client.println(" HTTP/1.1");
    client.println("Host:");
    client.println("User-Agent: Arduino/1.0");
    client.println("Connection: close");
    client.println("Content-Type: application/x-www-form-urlencoded; charset=UTF-8");
    client.print("Content-Length: ");
    client.println(len);
    client.println();
    client.print(data);
    restartnet = 0;
     data[0] = 0;
     Serial.print("data after sucessfull connection");
     Serial.println(data);
     Serial.print("freeMemory after connection");
     Serial.println(freeMemory());
    lastConnectionTime = millis();
   
  } else {
    
     Serial.println(F("Failed"));
     data[0] = 0;
   
  }
}

, 👍0

Обсуждение

Вы имеете в виду эту строчку? sprintf(strt, "te=%d", temp); - Вы уверены, что temp будет иметь только 2 цифры? Какой тип temp? Вы не включили заявление об этом в свой вопрос. И почему вы делаете все вызовы strcat ()? Почему бы просто не использовать snprintf с большей строкой формата, включая все данные вместе?, @chrisl

не похоже, что данные достаточно велики, @Juraj

А при использовании snprintf () разве вы не должны также указать максимальное количество символов для записи, так как эта функция предназначена для этого?, @chrisl

@chrisl ttemp-это значение температуры, я пытался это сделать, но получаю ошибки, новые для sprintf, поэтому не знаю, как реализовать, чтобы сделать строку, @user2037091

@Juraj новичок в sprintf , не знаю, как с этим справиться , что мне тогда нужно делать?, @user2037091

размер массива должен отражать количество символов, которые вы объединяете в него. есть ли в этом смысл?, @Juraj

@Juraj Да, на самом деле я до сих пор не знаю, почему моя система выходит из строя., @user2037091

@Juraj можете ли вы показать мне пример , как объявить глобальный символ ,который меняет статус, например, вкл., выкл., @user2037091

вы переписываете память другой переменной, если записываете из выделенного пространства. похоже, вы пишете примерно на 30 символов больше, чем размер ваших массивов " data[10]"., @Juraj

@Juraj я получил это, я изменил размер на 30. система повторно использует [30] память после использования?, @user2037091

подсчитайте символы и создайте достаточно большой массив. Я сказал еще 30, так что, думаю, 40. это локальная переменная, выделенная в "стеке". https://en.wikipedia.org/wiki/Stack-based_memory_allocation, @Juraj

@Juraj После перехода на [30] system works теперь выглядит нормально, если вы не возражаете, можете ли вы показать мне пример, чтобы поместить большие строки в sprintf ? поскольку моя цель-отправить данные на сервер с помощью webservice, я использовал strcat вместо sprintf проблема с strcat ( мне нужно каждый раз опустошать, @user2037091

sprintf_P(buff, PSTR("%-15s|%d-%02d-%02d %02d:%02d:%02d|% 5d|% 5d|% 3u|"), eventLongLabels[ix], year(t), month(t), day(t), час(t), минута(t), секунда(t), события[ix].value1, события[ix]. value2, события[ix].count); https://www.cplusplus.com/reference/cstdio/printf/, @Juraj


1 ответ


Лучший ответ:

4

В этом коде есть довольно много моментов, которые можно было бы улучшить. Основные из них уже были показаны в комментариях:

  1. буфер данных был недостаточно велик, чтобы вместить всю строку, что приводит к переполнению буфера, повреждению памяти и, в конечном счете, к сбою, который вы испытываете.

  2. Вторым параметром snprintf() должен быть размер предоставленного буфера.

Здесь я добавлю несколько моментов, которые, хотя и не совсем дефекты этой программы, могли бы помочь улучшить ее и сэкономить память.

Здесь:

char current[4];
// ...
if (val)
    snprintf(current, "YES");
else
    snprintf(current, "NO");

вы не используете текущий буфер для построения строки, а только для хранения одной из двух ранее существовавших строк (литералов "YES" и "NO"). которые уже хранятся в памяти. Вместо того чтобы делать копию, вы можете повторно использовать эти уже существующие строки и сделать current указателем на соответствующую строку:

const char *current;
// ...
if (val)
    current = "YES";
else
    current = "NO";

Это экономит только два байта (размер буфера минус размер указателя), но этот шаблон происходит несколько раз в программе, и экономия складывается.

Теперь еще одна небольшая оптимизация. Здесь:

char strt[6];
sprintf(strt, "te=%d", temp);
strcpy(data, strt);

вам не нужен дополнительный strt-буфер, так как вы можете записывать данные непосредственно в буфер данных. А еще лучше, вы можете записать все в буфер за один вызов snprintf():

snprintf(data, sizeof data,
        "te=%d&ti=%02d:%02d&mot=%s,%s,%s&mo=%s&hum=%d",
        temp, t.hour, t.min, ventionoroff, Foggeronoroff, current,
        Exhuastonoroff, hum);

Если вам не нравится такой подход и вы предпочитаете записывать данные в отдельные вызовы snprintf (), вы можете сделать это без использования вспомогательных буферов. Вы должны запомнить (с помощью указателя), где в буфере вы закончили предыдущую запись, и передать этот адрес следующему вызов snprintf (). Обратите внимание, что вы также должны отслеживать комнату , которая все еще доступна, что легко сделать со вторым указателем, указывающим на конец буфера:

char *p = data;                  // текущая позиция записи
char *end = data + sizeof data;  // конец буфера
p += snprintf(p, end - p, "te=%d", temp);
p += snprintf(p, end - p, "&ti=%s", today);
// ...
,

snprintf(data, sizeof data, "te=%d&ti=%d&mot=%s,%s,%s&mo=%s&hu=%d", temp, today, ventionoroff, Foggeronoroff, current, Exhuastonoroff, hum); 'today' actualy rtc время , но я получаю 825 в этом символе не время , я серийно напечатал сегодня, и у меня есть время, но отправка 825 на сервер не знает, откуда он пришел, @user2037091

@user2037091: сегодня " был массивом char` в исходном коде. Во всяком случае, я изменил ответ, чтобы напечатать "t.hour" и "t.min" вместо этого. Это экономит дополнительный вспомогательный буфер., @Edgar Bonet