Линейное меню с использование PROGMEM для дисплея 1602

mambo174

✩✩✩✩✩✩✩
9 Окт 2023
7
0
Доброго дня. Стоит задача написать линейное меню настроек. Настройки сохраняются в progmem память, решил сначала потестировать и понять как работает на этом примере https://github.com/AlexGyver/tutori...nuLinearOptiPROGMEM/menuLinearOptiPROGMEM.ino
Код прилагаю ниже, плата используется esp32. При компиляции выдает вот такую ошибку
invalid conversion from 'const char*' to 'int' [-fpermissive]
printFromPGM(names[i]);


C++:
// пример с оптимизированным линейным меню
// оптимизировано очищение дисплея
// названия засунуты в PROGMEM вместо оперативки
// менять значения можно нажатым поворотом, или КЛИКНУТЬ, курсор изменится, и крутить
// значение меняется быстрее при быстром повороте

#define LINES 4       // количество строк дисплея
#define SETTINGS_AMOUNT 7  // количество настроек
#define FAST_STEP 5   // скорость изменения при быстром повороте

// пины энкодера
#define CLK 2
#define DT 3
#define SW 4

#include "GyverEncoder.h"
Encoder enc(CLK, DT, SW);  // для работы c кнопкой

#include <LiquidCrystal_I2C.h>
LiquidCrystal_I2C lcd(0x27, 20, 4); // адрес 0x27 или 0x3f

int vals[SETTINGS_AMOUNT];  // массив параметров
int8_t arrowPos = 0;
bool controlState = 0;  // клик

// названия параметров
const char name1[] PROGMEM = "Speed";
const char name2[] PROGMEM = "Temp";
const char name3[] PROGMEM = "Mode";
const char name4[] PROGMEM = "Direction";
const char name5[] PROGMEM = "Limit";
const char name6[] PROGMEM = "Color";
const char name7[] PROGMEM = "Timeout";

// объявляем таблицу ссылок
const char* const names[] PROGMEM = {
  name1, name2, name3, name4, name5, name6, name7,
};

void setup() {
  //Serial.begin(9600);
  enc.setType(TYPE2);
  enc.setFastTimeout(100);

  lcd.init();
  lcd.backlight();
  printGUI();
}

void loop() {
  enc.tick();

  // смена контроля
  if (enc.isClick()) {
    controlState = !controlState;
    printGUI();
  }

  if (enc.isTurn()) {
    int increment = 0;  // локальная переменная направления

    // получаем направление
    if (!controlState) {
      if (enc.isRight()) increment = 1;
      if (enc.isLeft()) increment = -1;
      arrowPos += increment;  // двигаем курсор
      arrowPos = constrain(arrowPos, 0, SETTINGS_AMOUNT - 1); // ограничиваем
    }

    increment = 0;  // обнуляем инкремент
    if ((controlState && enc.isRight()) || enc.isRightH()) increment = 1;
    if ((controlState && enc.isLeft()) || enc.isLeftH()) increment = -1;
    
    if (controlState && enc.isFastR()) increment = FAST_STEP;
    if (controlState && enc.isFastL()) increment = -FAST_STEP;
    vals[arrowPos] += increment;  // меняем параметры

    printGUI();
  }
}

void printGUI() {
  static int8_t screenPos = 0; // номер "экрана"
  static int8_t lastScreen = 0; // предыдущий номер "экрана"

  screenPos = arrowPos / LINES;   // ищем номер экрана (0..3 - 0, 4..7 - 1)
  if (lastScreen != screenPos) lcd.clear(); // если экран сменился - очищаем
  lastScreen = screenPos;

  for (byte i = 0; i < LINES; i++) {  // для всех строк
    lcd.setCursor(0, i);              // курсор в начало

    // если курсор находится на выбранной строке
    smartArrow(arrowPos == LINES * screenPos + i);  // рисуем стрелку или пробел

    // если пункты меню закончились, покидаем цикл for
    if (LINES * screenPos + i == SETTINGS_AMOUNT) break;

    // выводим имя и значение пункта меню
    printFromPGM(&names[LINES * screenPos + i]);
    lcd.print(F(": "));
    lcd.print(vals[LINES * screenPos + i]);
    lcd.print(F("  ")); // пробелы для очистки
  }
}

// очень хитрая функция для печати из PROGMEM
void printFromPGM(int charMap) {
  uint16_t ptr = pgm_read_word(charMap);    // получаем адрес из таблицы ссылок
  while (pgm_read_byte(ptr) != NULL) {      // всю строку до нулевого символа
    lcd.print(char(pgm_read_byte(ptr)));    // выводим в монитор или куда нам надо
    ptr++;                                  // следующий символ
  }
}

void smartArrow(bool state) {  // рисует стрелку, галку или пробел
  lcd.write(state ? (controlState ? 62 : 126) : 32);
}
 

Старик Похабыч

★★★★★★★
14 Авг 2019
4,282
1,306
Москва
Может потому что функция printFromPGM ждет передачи целого числа, а не массив символов ?
Попробуйте изменить описание функции так:
C++:
void printFromPGM(const char charMap[]) {
 

mambo174

✩✩✩✩✩✩✩
9 Окт 2023
7
0
Может потому что функция printFromPGM ждет передачи целого числа, а не массив символов ?
Попробуйте изменить описание функции так:
C++:
void printFromPGM(const char charMap[]) {
Пробовал, ошибка все равно
invalid conversion from 'const char*' to 'char' [-fpermissive]
printFromPGM(names[LINES * screenPos + i]);
Может от версии arduino ide зависить?
 

vortigont

★★★★★★✩
24 Апр 2020
1,021
542
Saint-Petersburg, Russia
под esp32 progmem не нужен

перепишите вот так
C++:
// неочень хитрая функция для печати из PROGMEM
void printFromPGM(const char* charMap) {
    lcd.print(charMap);
}
и выше по тексту
Код:
    // выводим имя и значение пункта меню
    printFromPGM( names[LINES * screenPos + i]);   // убран амперсант &