Цикл, progmem и strlen_P - прошу помощи

Dinosaur
Dinosaur аватар
Offline
Зарегистрирован: 01.01.2018

Добрый день, камрады

Пытабюсь разобраться с простейшим скетчем:


const char array_1[] PROGMEM = "Period";
const char array_2[] PROGMEM = "Work";
const char array_3[] PROGMEM = "Stopp";

const char* const names[] PROGMEM = {
  array_1, array_2, array_3,
};

void setup() {
  Serial.begin(9600);
  for (byte i = 0; i < 3; i++) {
    byte stringlenght = strlen_P(names[i]);
    Serial.print("string ");
    Serial.print(i);
    Serial.print(" lenght - ");
    Serial.println(stringlenght);
  }
}
void loop() {}

В порту ожидаю увидеть:

string 0 lenght - 6
string 1 lenght - 4
string 2 lenght - 5
 
однако вижу:
 
string 0 lenght - 77
string 1 lenght - 3
string 2 lenght - 3
 
При этом если запрашиваю strlen_P(names[0]), strlen_P(names[1]), strlen_P(names[2]) получаю корректные значения. Вопрос - что я делаю не так? Уже бубен и весь мозг сломал.

 

b707
Offline
Зарегистрирован: 26.05.2017

в строке 5 PROGMEM уберите - заработает :)

проблема в том. что у вас не только строчки лежат в ПРОГМЕМ, но и ссылки на них

Dinosaur
Dinosaur аватар
Offline
Зарегистрирован: 01.01.2018

b707 пишет:

в строке 5 PROGMEM уберите - заработает :)

проблема в том. что у вас не только строчки лежат в ПРОГМЕМ, но и ссылки на них

Спасибо за наводку, заработало. Но смущает то, что во всех уроках по работе с прогрем, которые мне попались, используется именно такая конструкция (в прогмем лежат также и ссылки), собственно этот скетч был взят из одного из таких уроков. Также не пойму почему если запрос делаю не через цикл, а указывая адрес ссылки в массиве то значения возвращаются правильные. Можете объяснить?

DetSimen
DetSimen аватар
Offline
Зарегистрирован: 25.01.2017

это известные грабли, значения из массивов, которые лежат в прогмем надо читать не через оператор индекса, а через pgm_read_xxx()

Dinosaur
Dinosaur аватар
Offline
Зарегистрирован: 01.01.2018

DetSimen пишет:

это известные грабли, значения из массивов, которые лежат в прогмем надо читать не через оператор индекса, а через pgm_read_xxx()

не подскажете как это корректно сделать, а то не соображу? Строка byte stringlenght = strlen_P(pgm_read_byte(&(names[i]))); тоже не приводит к получению корректных значений.

DetSimen
DetSimen аватар
Offline
Зарегистрирован: 25.01.2017

давай папожжэ, я щас занят маенька

DetSimen
DetSimen аватар
Offline
Зарегистрирован: 25.01.2017

можешь пока с этим азнакомица

http://arduino.ru/forum/programmirovanie/vopros-k-znatokam-otlitym-v-bronze

DetSimen
DetSimen аватар
Offline
Зарегистрирован: 25.01.2017

краткая выжимка, если индексы у тебя константы, будет отдавать правильно names[0], names[1] и т.д.

Если индекс - переменная, будь добр вычислять адреса сам и читать через pgm_read_xxx()

b707
Offline
Зарегистрирован: 26.05.2017

Dinosaur пишет:

не подскажете как это корректно сделать, а то не соображу? Строка byte stringlenght = strlen_P(pgm_read_byte(&(names[i]))); тоже не приводит к получению корректных значений.

читать надо word , а не byte, потому что адреса памяти 16-битные

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

byte stringlenght = strlen_P(pgm_read_word(&(names[i])));

Dinosaur
Dinosaur аватар
Offline
Зарегистрирован: 01.01.2018

DetSimen пишет:

можешь пока с этим азнакомица

http://arduino.ru/forum/programmirovanie/vopros-k-znatokam-otlitym-v-bronze

Почитал. единственное что понял - это компилятор оптимизирует код таким образом )) Попытался сделать по совету Ворот byte stringlenght = strlen_P(pgm_read_ptr_near(names+i)); - ничего не получилось (видимо я смысл совета не понял)

Dinosaur
Dinosaur аватар
Offline
Зарегистрирован: 01.01.2018

b707 пишет:

читать надо word , а не byte, потому что адреса памяти 16-битные

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

byte stringlenght = strlen_P(pgm_read_word(&(names[i])));

Пробовал - не помогает :(

Dinosaur
Dinosaur аватар
Offline
Зарегистрирован: 01.01.2018

DetSimen пишет:

краткая выжимка, если индексы у тебя константы, будет отдавать правильно names[0], names[1] и т.д.

Если индекс - переменная, будь добр вычислять адреса сам и читать через pgm_read_xxx()

 

Нда, я - дебил, который не может прочесть написанное. byte stringlenght = strlen_P(names[i]); - привело к правильному результату. Всем спасибо.

b707
Offline
Зарегистрирован: 26.05.2017

Dinosaur пишет:

Нда, я - дебил, который не может прочесть написанное. byte stringlenght = strlen_P(names[i]); - привело к правильному результату. Всем спасибо.

что-то не понял... так у вас так и было в первом сообщении:)

весь код можете привести?

Dinosaur
Dinosaur аватар
Offline
Зарегистрирован: 01.01.2018

b707 пишет:
что-то не понял... так у вас так и было в первом сообщении:) весь код можете привести?

Чёрт, еще меньше стал понимать. Действительно от чего ушли - к тому и пришли:


const char array_1[] PROGMEM = "Period";
const char array_2[] PROGMEM = "Work";
const char array_3[] PROGMEM = "Stopp";

const char* const names[] = {
  array_1, array_2, array_3,
};

void setup() {

  Serial.begin(9600);

  for (byte i = 0; i < 3; i++) {
    byte stringlenght = strlen_P(names[i]);
    Serial.print("string ");
    Serial.print(i);
    Serial.print(" lenght - ");
    Serial.println(stringlenght);
  }
}
void loop() {}

Но теперь в порту:

string 0 lenght - 6
string 1 lenght - 4
string 2 lenght - 5
 
Звезды на небе сошлись по другому?
Dinosaur
Dinosaur аватар
Offline
Зарегистрирован: 01.01.2018

Тьфу, прогмем потерял в процессе. Пошел дальше изучать русские буквы.

Dinosaur
Dinosaur аватар
Offline
Зарегистрирован: 01.01.2018

В таком виде работает (оба варианта):


const char array_1[] PROGMEM = "Period";
const char array_2[] PROGMEM = "Work";
const char array_3[] PROGMEM = "Stopp";
const char array_4[] PROGMEM = "Oh";

const char* const names[] PROGMEM = {
  array_1, array_2, array_3, array_4,
};

void setup() {

  Serial.begin(9600);

  for (byte i = 0; i < 4; i++) {
    byte stringlenght = strlen_P(pgm_read_ptr_near(names+i));
    byte stringlenght = strlen_P((char*)pgm_read_word(&(names[i])));
    Serial.print("string ");
    Serial.print(i);
    Serial.print(" lenght - ");
    Serial.println(stringlenght);
  }
}
void loop() {}

Теперь точно всем спасибо! Не вполне понял почему именно так, пока запомню что слова "вилька" и "тарэлька" пишутся без мягкого знака.

DetSimen
DetSimen аватар
Offline
Зарегистрирован: 25.01.2017

Нальёшь при случае. :) 

Dinosaur
Dinosaur аватар
Offline
Зарегистрирован: 01.01.2018

DetSimen пишет:
Нальёшь при случае. :)

С радостью!