Serial read в char[] - глюк

whoim
Offline
Зарегистрирован: 03.11.2011

 Сначала думал МК глючит, я ему полярку намедни перепутал до треска и дыма, иногда перешивать приходится теперь (но для тренировок сойдет). Однако на новом МК та ж беда (Атмега8Л)

сhar RX_char[] = "";

void RX() {
  byte RX_i = 0;
    char b;
    RX_char[0] =  '\0';
    while (Serial.available()) {
      b = Serial.read();
      if(b == 13) break;
      RX_char[RX_i] =  b;
      RX_i++;
      RX_char[RX_i] =  '\0';
      //if(RX_i > 3) break;
    }
}

Если отослать через терминал больше 4-х символов - МК уходит в перезагрузку (начинает исполняться setup()). За этим и стоит закомменченная строчка if(RX_i > 3), так хотя бы данные считываются при следующем цикле из буфера. Отчего такое происходит и как побороть?

whoim
Offline
Зарегистрирован: 03.11.2011

 Да, и еще: отчего sizeof(RX_char) всегда равен единице?

step962
Offline
Зарегистрирован: 23.05.2011

whoim пишет:

 Да, и еще: отчего sizeof(RX_char) всегда равен единице?

Ибо

char RX_char[]="";

 Здесь вы задали массив символов, под который выделена одна-единственная ячейка памяти (которой хватает лишь на то, чтобы записать туда стандартный для C терминатор строки "\0"). При попытке записи в эту переменную более чем одного символа (переменные выравниваются на границу слова) происходит выход за границы той области памяти, которая отведена под массив. С непредсказуемыми последствиями. В вашем случае это может быть перезапись какой-либо важной переменной (например, указателя на функцию), что и приводит к сбросу МК. Собираетесь записывать в этот массив, например, до 10 символов? Ну и произведите соответствующую инициализацию:

char RX_char[]="0123456789"; // инициализация массива длиной 11 байт (11-й байт - под терминатор "\0" - добавляется автоматически)
char TX_char[11]; // те же яйца, только ... без инициализации содержимого

 После этого sizeof(RX_char) всегда будет равен 11.

whoim
Offline
Зарегистрирован: 03.11.2011

 В том то и дело, что очень хочется динамический массив. Вроде такой пример был описан в хелпе на arduino.cc. То есть инициализируем как у меня и дописываем в нужном месте \0..

step962
Offline
Зарегистрирован: 23.05.2011

 А почему очень хочется? Для экономии памяти? А не думали, сколько этой самой памяти займет информация, необходимая для учета выделенных участков памяти и возвращения в кучу болше неиспользуемых участков?

Ради 1-2 строк переменной длины, по-моему, совершенно не стоит заморачиваться. Ради десятка коротких строк - тоже. Овчинка выделки не стоит.

Но если все же очень хочется, тогда, например, так:

В следующем фрагменте программы мы динамически выделяем память под строку переменной длины и копируем туда исходную строку
// стандартная функция strlen подсчитывает
// количество символов в строке
int length = strlen(src_str);
// выделить память и добавить один байт
// для завершающего нулевого байта
char* buffer = new char[length + 1];
strcpy(buffer, src_str);
// копирование строки

 

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

whoim
Offline
Зарегистрирован: 03.11.2011

 Хотелось именно экономить память, но я вижу - с динамическими только больше ее уходит :) Спасибо!

Просто разные данные надо читать, и поменьше и побольше, хотелось универсальную функцию чтения написать которая возвращала бы массив нужной длинны (прочитано до #13).  Но, вижу, проще сделать по размеру максимально передаваемых данных.

 

Спасибо!