Преобразование char в строку в программе Arduino

Я начал изучать Arduino и хорошо разбираюсь в Java и Python. В программе Arduino мне нужно, чтобы ввод символов через Serial сохранялся в переменной String. Из моего предыдущего опыта программирования я знал, что код, подобный приведенному ниже, выдаст ошибку, поскольку char не может быть преобразован в String таким образом.

void loop() {
  if(Serial.available()) {
     String s=(char)Serial.read();
  }
}

Как и ожидалось, приведенный выше код выдает ошибку при компиляции. Но когда я сначала определил s, а затем присвоил его значение на отдельном шаге в void loop(), я не получил никакой ошибки.

void loop() {
  if(Serial.available()) {
     String s;
     s=(char)Serial.read();
  }
}

Приведенный выше код не выдает ошибок, несмотря на то, что он почти аналогичен первому коду. Я подозреваю, что это как-то связано с тем, что String является классом. Можно ли сказать, что происходит?

, 👍1


4 ответа


0

У меня нет большого опыта работы с типом String Arduino, однако большинство людей (включая меня) не советуют его использовать. Поскольку Arduino имеет только 1 КБ SRAM, а тип String имеет собственное скрытое выделение памяти, у вас может закончиться память, даже если вы об этом не знаете, что приведет к сбою/зависанию программ без понимания того, что происходит. .

Вместо этого используйте массивы символов (например, char str[10]), где вы точно знаете, что зарезервировано.

Однако, чтобы ответить на ваш вопрос, что я ожидаю, поскольку String является классом, в этом классе есть конструктор (копирование), который берет char и преобразует его в String.

,

1

это не специфическая ошибка Arduino, вы пытаетесь объявить и инициализировать переменную в одном выражении, что вызывает проблему. Как вы уже поняли. Сначала объявить переменную

String s;

и его инициализация другим оператором сделает всю работу за вас

s=blabla

Надеюсь, это поможет. PS, попробуйте в следующий раз опубликовать ошибку, которую вы получите во время процесса сборки :)

ОБНОВЛЕНО: Я думаю, что это нуждается в большем объяснении. В основном, почему вы не можете одновременно объявлять и инициализировать в этом случае, потому что Serial.read является синхронным запросом. Объявление объекта требует выделения для него пространства, запуска каких-либо конструкторов и прочего, а также выполнение операций, в то время как Serial.read() является операцией блокировки ввода-вывода. Вы можете объявить и инициализировать переменную класса String, если она является строковой константой, но не с чем-то вроде get_input или Serial.read

ОБНОВЛЕНИЕ 2: Далее вот что я нашел для вас.

http://www.cplusplus.com/reference/string/string/string/

По-видимому, класс String имеет конструктор копирования, что означает, что при объявлении переменной, которую вы инициализируете, он одновременно использует конструктор копирования и требует ADDRESS для действительной строки (знайте, что вы можете использовать константу, потому что C++ имеет дело со всеми строки как адрес их первого символа). В вашем случае конструктор вызвал ошибку, потому что вы указали на undefined(Serial.read() ).

String mystring=Serial.read(); //ошибка, использует конструктор копирования

Однако это сработает

String mystring="hey juliet!" ; //использует конструктор копирования, который переводит адрес в символ

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

String mystring; //использует конструктор пустой строки - пока нормально
mystring=Serial.read(); // использует перегруженный оператор = --okay

,

1

Вы неправильно поняли Serial.read(): он не возвращает String или что-то в этом роде. как массив символов, но целое число, представляющее только последний байт во входном буфере, который не был прочитан.

Что вы, вероятно, захотите сделать, так это интерпретировать эти входящие байты как char и накапливать их в String.

Например, так:

String s="";
while(Serial.available()) {
  // пока в буфере есть байты
  s+=(char)Serial.read(); // интерпретируем int как char и добавляем символ к s
}

Поскольку использование String может легко привести к сбоям, вам следует избегать динамического выделения памяти, используя массивы символов фиксированного размера:

#define MAX_LEN 64
char s[MAX_LEN];
uint8_t i;
while (serial.available() && i<MAX_LEN) {
  s[i]=(char) Serial.read();
  i++;
}

Примечание: когда вы дойдете до этого места, вам все равно придется обрабатывать данные, когда вы хотите, чтобы они были готовы к обработке (например, обнаружение \n и установка соответствующего флага).

,

Я правильно понимаю `Serial.read()`. Я знаю, что он возвращает целое число, поэтому я поставил перед ним `(char)`. Также в моей программе я не хочу, чтобы последовательность символов сохранялась в String s, только один символ, и поэтому `Serial.read()`. Я просто тестировал и выяснил что-то неизвестное и хочу знать только причину этого., @Big Brother


0

Это решит проблему: void loop() { если(серийный.доступный()) { Строка s=(char*)Serial.read(); } Это связано с тем, что в C: строки определяются как массив символов. Вы не можете назначить примитив массиву...

Я предполагаю, что приведение к указателю может быть неявным, как во втором примере..

,