Опять PROGMEM

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

Добрый день, камрады. Снова взялся колупать PROGMEM и снова хожу по граблям. Вот код, работает как я ожидаю, в сериал выводятся значение "    FWD" (соотвественно если вызываю foo(1), то выводится "    REW", если foo(2), то выводится "FWD/REW".

const char name_30[] PROGMEM =  "    FWD";
const char name_31[] PROGMEM =  "    REW";
const char name_32[] PROGMEM =  "FWD/REW";
const char *const directionNames[] PROGMEM = {name_30, name_31, name_32 };

void setup() {
  Serial.begin(115200);
   foo(0);
}

void foo (const uint16_t _value) {
  for (uint16_t i = 0; i < 7; i++) Serial.print((char)pgm_read_byte_near(directionNames[_value] + i));
}

void loop() {
  // put your main code here, to run repeatedly:
}

Но стоит продолжить мысль и возжелать вывести несколько значений - получаю кракозябры (даже если с одним аргементом пытаюсь вызвать foo более одного раза):

const char name_30[] PROGMEM =  "    FWD";
const char name_31[] PROGMEM =  "    REW";
const char name_32[] PROGMEM =  "FWD/REW";
const char *const directionNames[] PROGMEM = {name_30, name_31, name_32 };

void setup() {
  Serial.begin(115200);
 
  foo(0);                                                                                              

  foo(1);                                                                                              
 }

void foo (const uint16_t _value) {
  for (uint16_t i = 0; i < 7; i++) Serial.print((char)pgm_read_byte_near(directionNames[_value] + i));
}

void loop() {
  // put your main code here, to run repeatedly:
}

Что я делаю не так? 

rkit
Offline
Зарегистрирован: 23.11.2016

Сколько у тебя уровней вложенности progmem и сколько вызовов чтения из этой памяти?

И зачем ты вообще со строками работаешь посимвольно?

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

rkit пишет:

Сколько у тебя уровней вложенности progmem и сколько вызовов чтения из этой памяти?

М... Два выходит? (я не настоящий сварщик, маску на стройке нашёл)...

rkit пишет:

И зачем ты вообще со строками работаешь посимвольно?

Задача такая - есть массив char подготовленный для вывода на экран. Нужно на определенное место вставить в него значения параметров. Мой больной разум породил для этой задачи такую функцию (визуально работает как надо, хотя не исключаю возникновения подводных камней типа как в первом сообщении):

void addDirectionValue (char* buffer, const uint8_t value) {
    uint8_t bufSize = strlen_P(pgm_read_ptr_near(directionNames + value)) + 1;
    char bufferVal[bufSize];
    strcpy_P(bufferVal, pgm_read_ptr_near(directionNames + value));
    for (uint8_t i = 0; i < bufSize; i++) buffer[i + 12] = bufferVal[i];
}

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

Green
Offline
Зарегистрирован: 01.10.2015

...pgm_read_byte_near(&directionNames[_value] + i));

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

Green пишет:

...pgm_read_byte_near(&directionNames[_value] + i));

По Вашему не взлетело, а вот так получилось:

void addDirectionValue (char* buffer, const uint8_t value) {
  char *ptr = pgm_read_ptr_near(directionNames + value);
  for (uint8_t i = 0; i < strlen_P(pgm_read_ptr_near(directionNames + value)); i++) {
    buffer[12 + i] = pgm_read_byte_near(ptr++);
  }
}

 

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

И такой вариант тоже заработал:

void addDirectionValue (char* buffer, const uint8_t startPosition, const uint8_t value) {
  for (uint8_t i = 0; i < strlen_P(pgm_read_ptr_near(directionNames + value)); i++) {
    buffer[startPosition + i] = pgm_read_byte_near((char*)pgm_read_ptr_near(directionNames + value) + i);
  }
}

Вроде то что я хотел. Если более опытные товарищи скажут что я пытаюсь вырвать гланды через задницу, а после объяснят как это делать правильно - выслушаю с благодарностью.

Чтобы было понятно - названия параметров хранятся так:

const char name_30[] PROGMEM =  "    FWD";
const char name_31[] PROGMEM =  "    REW";
const char name_32[] PROGMEM =  "FWD/REW";
const char *const directionNames[] PROGMEM = { name_30, name_31, name_32 };

 

Green
Offline
Зарегистрирован: 01.10.2015
const char directionNames[] PROGMEM = "    FWD""    REW""FWD/REW";

void setup() {
  Serial.begin(115200);
  foo(0);
  foo(1);
  foo(2);
}

void foo(const uint16_t _value) {
  for (uint16_t i = 0; i < 7; i++)
    Serial.print((char)pgm_read_byte(&directionNames[_value * 7 + i]));
}

void loop() {
}

Не?

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

Dinosaur пишет:

Чтобы было понятно - названия параметров хранятся так:

const char name_30[] PROGMEM =  "    FWD";
const char name_31[] PROGMEM =  "    REW";
const char name_32[] PROGMEM =  "FWD/REW";
const char *const directionNames[] PROGMEM = { name_30, name_31, name_32 };

 

если перенести массив указателей directionNames[] в ОЗУ из ПРОГМЕМа (он небольшой, занимает мало) - то работать со строками станет занчительно проще.

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

b707 пишет:

если перенести массив указателей directionNames[] в ОЗУ из ПРОГМЕМа (он небольшой, занимает мало) - то работать со строками станет занчительно проще.

Это я понимаю, но все равно рано или поздно придётся с указателями и прогмемом разбираться.

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

Green пишет:
Не?

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