Сбой системы после использования 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;
}
}
@user2037091, 👍0
Обсуждение1 ответ
Лучший ответ:
В этом коде есть довольно много моментов, которые можно было бы улучшить. Основные из них уже были показаны в комментариях:
буфер
данных
был недостаточно велик, чтобы вместить всю строку, что приводит к переполнению буфера, повреждению памяти и, в конечном счете, к сбою, который вы испытываете.Вторым параметром
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
- Как использовать SPI на Arduino?
- Как решить проблему «avrdude: stk500_recv(): programmer is not responding»?
- Как создать несколько запущенных потоков?
- Как подключиться к Arduino с помощью WiFi?
- avrdude ser_open() can't set com-state
- Как узнать частоту дискретизации?
- Что такое Serial.begin(9600)?
- Я закирпичил свой Arduino Uno? Проблемы с загрузкой скетчей на плату
Вы имеете в виду эту строчку?
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