Сбой Arduino во время последовательной печати без очевидной причины
Я написал код Arduino, который продолжал падать, и я не мог понять, почему. Затем я максимально сократил код, чтобы увидеть проблему. Сокращенный код в настоящее время не делает ничего экстраординарного, кроме вывода некоторых строк в последовательной строке.
Это сокращенный код:
void setup()
{
Serial.begin(9600);
Serial.print("Begin\r\n");
send_wifi_beacon();
}
void loop()
{
delay(1000);
}
void send_wifi_beacon()
{
send_wlan_chip_command("AT+CIFSR");
Serial.print("notreached"); // эта часть никогда не достигается
send_data_over_network(); // нельзя удалить эту строку, иначе не произойдет сбой, что странно, так как это никогда не вызывается
}
void read_response_from_serial()
{
delay(2000);
Serial.print("==-1\r\n"); // здесь происходит сбой
}
void send_wlan_chip_command(char* command)
{
Serial.print("Sending command to wifi module: ");
Serial.print(command);
read_response_from_serial();
Serial.print("Command response: ");
}
// эта функция никогда не вызывается, так как сбой происходит до вызова, но ее нельзя удалить, иначе сбоя не произойдет
// и тогда его нельзя будет переделать, краха тоже не будет.
void send_data_over_network()
{
char number[3] = "12";
// номер символа[3] = "";
char length_of_payload[20] = "0123456789012345678"; // 20 цифр, если предположить, что 64-битное целое число является максимальным, на котором этот код когда-либо будет работать
// char length_of_payload[20] = "";
char *command;
command = malloc(26);
command = "AT+CIPSSEND";
strcat(command, number);
strcat(command, ",");
strcat(command, length_of_payload);
send_wlan_chip_command(command);
free(command);
}
Это соответствующий вывод:
Начать отправку команды на модуль Wi-Fi: AT+CIFSR==Начать
Отправка команды на модуль Wi-Fi: AT+CIFSR==Begin
Отправка команды на модуль Wi-Fi: AT+CIFSR==Begin
Отправка команды модулю Wi-Fi: AT+CIFSR==Begin
Это означает, что Arduino продолжает сбоить и перезагружаться. Это будет продолжаться вечно.
Странно то, что если я изменю следующие две строки на: (в функции "send_data_over_network", как в примере выше)
char number[3] = "1"; // изменено с => номер символа [3] = "";
char length_of_payload[20] = "123"; // изменено с => char length_of_payload[20] = "0123456789012345678";
Теперь вывод изменится на:
Я называю это поведение странным, поскольку оно не должно влиять на результат, потому что эта функция (send_data_over_network) никогда не вызывается в предыдущем примере сбоя.
Варианты устранения неполадок, которые я уже пробовал:
- Переустановив Arduino IDE, я пробовал несколько версий 1.8, 1.6, 1.4. 1,0
- Различные платы Arduino (Arduino Uno и Arduino Mega)
- Разные ноутбуки (поскольку я думал, что это может быть связано с проблемами питания моего ноутбука)
Возможно, это что-то очевидное, и я просто не вижу этого, но я уже потратил +16 часов на отладку, поэтому помощь будет очень признательна.
@KoKlA, 👍2
2 ответа
Лучший ответ:
Этот код выглядит неправильно:
Команда command = malloc(26);
command = "AT+CIPSSEND";
strcat(command, number);
strcat(command, ",");
strcat(command, length_of_payload);
send_wlan_chip_command(command);
Сначала вы выделяете 26 байт, затем создается новая строка, которую вы направляете к ней. Это происходит в памяти, которая не выделена (или перезаписывает другие данные).
Вместо
command = "AT+CIPSSEND";
использовать
strcpy(command, "AT+CIPSSEND");
Также убедитесь, что 26 байт достаточно, измените его на 128 байт, чтобы быть уверенным (проверьте нужный объем позже).
У вас почти наверняка не хватает памяти, и у вас есть коллизия стека с кучей. Динамическое выделение и освобождение памяти не является хорошей идеей, если у вас меньше 2 КБ ОЗУ для работы. Если вы используете malloc(), используйте его только для выделения буферного пространства, а затем повторно используйте буферы. Поместите свой тестовый код полностью в настройку и посмотрите, что произойдет. Также проверьте объем ОЗУ, выделенный во время компиляции, он может быть больше, чем вы думаете.
char *buf1;
char *buf2;
void setup() {
buf1 = (char *) malloc(10);
buf2 = (char *) malloc(10);
.
.
// тестовый код здесь
}
- Последовательная связь между двумя Arduino (запрос и получение)
- Программирование пользовательских Arduino Mega с Arduino Uno
- 16-герцовая плата Uno R3 против платы Arduino Uno R3
- Отладка различного поведения последовательного приема/отправки между Uno и Mega
- Последовательная связь между Arduino
- Как разделить входящую строку?
- Как использовать SPI на Arduino?
- Как узнать частоту дискретизации?
Если вы решите использовать malloc() и строки, обязательно инициализируйте память нулями, иначе strcat не будет работать должным образом., @jose can u c
Не "подозрительно". Это не правильно". Нельзя добавить к строковой константе... Кроме того, вы хотите использовать
strcpy
, а неstrcat
в своем исправлении., @Johnny MoppАх, я не знал, что я не могу добавить к строковой константе. Но это имеет смысл, поскольку находится в другой области памяти. Одна вещь, которую я до сих пор не понимаю, это то, как именно это привело к сбою, поскольку функция на самом деле так и не была достигнута. Или было? Поэтому я бы предположил, что он рухнет после этого, а не до вызова функции. Кто-нибудь может это объяснить? Может ли это быть связано с оптимизацией компилятора? Я принял ваш ответ как решение, но голосование еще не засчитывается. Спасибо вам обоим., @KoKlA
@JohnnyMopp Спасибо за хорошие замечания, я улучшил ответ., @Michel Keijzers
@KoKIA, вы уверены, что функция не вызывалась? Самый простой способ - добавить оператор печати до и после неправильного кода ... и желательно добавить немного после каждой команды печати, чтобы убедиться, что информация была сброшена (не уверен, что задержка абсолютно необходима). Но операторы печати очень помогают (если отладка невозможна, как в Arduino)., @Michel Keijzers
@KoKlA Кроме того, даже если бы ваш код работал, у вас возникла бы утечка памяти, поскольку вы немедленно переназначили бы значение, возвращаемое из
malloc
. Эта память потеряна. Кроме того, из-за переназначения вы получите ошибку вfree()
., @Johnny Mopp@MichelKeijzers круто. вы правы, я просто добавил задержку (x) между моими последовательными выходами, и теперь я мог видеть, что на самом деле происходит сбой в функции, и функция на самом деле вызывается. Это означает, что Arduino вылетает быстрее, чем серийный номер может печатать свои символы. Теперь все имеет смысл, я бы никогда не подумал об этом. Большое спасибо, @KoKlA
Рассмотрите возможность использования
alloca()
вместоmalloc()
. Он размещается в стеке, а не в куче, и автоматически освобождается при выходе из функции и отбрасывании кадра стека., @Majenko@KoKIA Добро пожаловать ... добавление операторов печати занимает в основном время, но это может иметь значение между догадкой и знанием., @Michel Keijzers
@Majenko спасибо за совет alloca(), я обязательно им воспользуюсь., @KoKlA
@Majenko и @KoKlA:
alloca()
наиболее полезна, когда вы заранее не знаете требуемый размер. Если этот размер является константой времени компиляции, проще просто объявитьchar command[26]
., @Edgar Bonet