Это сколько же "всяких переменных" надо объявить, чтобы израсходовать более полутора килобайт памяти...
Могу предположить, что Ваши переменные, которые забивают память, - это текстовые константы. Если так, их можно оставить в PROGMEM, не копируя в оперативную память.
Sketch uses 59 462 bytes (23%) of program storage space. Maximum is 253 952 bytes.
Global variables use 3 120 bytes (38%) of dynamic memory, leaving 5 072 bytes for local variables. Maximum is 8 192 bytes.
)))
Такой массив был для меня удобен в плане обращения к нему
int timeLightTimer[4][2][2][2] = {}; // удалить позже
//byte timeLightTimer[selectedLight][selectedLightTimerInterval][selectedLightTimerOnOff][selectedTimerHM];
первая строка - цвет света - синий, красный, белый, зелёный
вторая строка - интервал - первый, второй
третья строка -действие - включение, выключение
четвёртая строка - время - часы, минут.
В таком виде массив был для меня более читабелен, чем inttimeLightTimer[32], так я вижу сколько цветов, сколько интервалов времени.
А про удалить, тут полностью прав Клапауций 234, нужно было просто удалить клавишей Delete.
Вместо этого массива я перешёл на класс, и теперь вся эта информация будет у меня хранится в созданных объектах.
Просто библиотеку я уже написал, а вот сам проект на этот класс не перевёл, поэтому в коде есть строки со сторым исполнением.
Так просто нельзя делать или это как то обходится?
orcsin,
Вы, похоже, не понимаете. что делаете, а пытаетесь методом тыка поймать комбинацию при которой хотя бы скомпилируется.
Ну, вот что Вы написали:
const PROGMEM byte RELAY_TEMPERATURE1 = 1;
Вы понимаете. что означает слово const? Это означает КОНСТАНТА. Ну, а если она конастанта, то нафига ж Вы её менять пытаетесь?
pgm_read_byte(&RELAY_TEMPERATURE1)
Константы не меняются в процессе работы программы (а если и меняются, то не так и делать этого в порядочной программе не стоит).
Кроме того, Вы знаете, что должно идти после слова case? Константа интегрального типа, а Вы что туда пихаете?
Почитайте книжку по языку (я Вам уже советовал это в посте №9). Без этого Вы так и будете как слепой котёнок тыкаться, авось компилятор схавает. Но он ведь может схавать, но скомпилировать совсем не тот код, которого Вы ожидаете.
orcsin, объясните, как именно Вы пытаетесь сэкономить память? И при чем здесь PROGMEM?
В данном случае у меня пролема с ОЗУ. Её осталось мало. Выше мне подсказали PROGMEM, благодаря которой можно часть переменых переместить во флешь память. Ну на сколько я это понял.
Вы, похоже, не понимаете. что делаете, а пытаетесь методом тыка поймать комбинацию при которой хотя бы скомпилируется.
Ну, вот что Вы написали:
const PROGMEM byte RELAY_TEMPERATURE1 = 1;
Вы понимаете. что означает слово const? Это означает КОНСТАНТА. Ну, а если она конастанта, то нафига ж Вы её менять пытаетесь?
pgm_read_byte(&RELAY_TEMPERATURE1)
Почитайте книжку по языку (я Вам уже советовал это в посте №9). Без этого Вы так и будете как слепой котёнок тыкаться, авось компилятор схавает. Но он ведь может схавать, но скомпилировать совсем не тот код, которого Вы ожидаете.
1. Да не пытаюсь вроде осозновать то что пишу :)
2. Я вроде не пытаюсь изменить константу, а только вызываю её значение через
pgm_read_byte(&RELAY_TEMPERATURE1).
Или я что то не понимаю?
Несколько книг я прочёл, много дало, но видимо там не всё есть с чем приходится сталкиваться. Если посоветуете какую то конкретную книгу, буду очень благодарен. Я про классы прочёл несколько книг, и только в 5ой было написано так, что хоть как то стало понятно.
И про case,
const PROGMEM byte RELAY_TEMPERATURE1 = 1;
const byte RELAY_TEMPERATURE1 = 1;
в этих двух строках же вроде один и тот же тип указан, просто один займёт место в ОЗУ, а другой нет. Или я опять что то упустил? На сколько я понял то PROGMEM используется для этого, что бы освободить ОЗУ.
Выше мне подсказали PROGMEM, благодаря которой можно часть переменых переместить во флешь память.
ну, ок - ты что-то где-то прочитал.
а, как ты собрался менять переменные, которые возможно изменить, переписав флеш?
*так, чисто практический интерес имею - хочу писать флеш из исполняемого кода.
Возможно я не понял ответа, но я переношу в PROGMEM только те переменные, которые не собираюсь менять на протяжении всей программы. Тоесть только константы.
2. Я вроде не пытаюсь изменить константу, а только вызываю её значение
Понятия "вызывать значение" нет. Вы пытаетесь присвоеить ей значение, а это и есть поменять её. Она у Вас при описании была 1, а Вы пытаетесь туда что-то другое запихать.
orcsin пишет:
И про case,
const PROGMEM byte RELAY_TEMPERATURE1 = 1;
const byte RELAY_TEMPERATURE1 = 1;
в этих двух строках же вроде один и тот же тип указан, просто один займёт место в ОЗУ, а другой нет. Или я опять что то упустил? На сколько я понял то PROGMEM используется для этого, что бы освободить ОЗУ.
Ни в том ни в другом случае RELAY_TEMPERATURE1 не будет занимать ОЗУ. Но и поменять её нельзя, т.к. костанта. Вот Вы сказали, что она 1 - так она 1 и будет всегда.
Давайте, тоже приложу свои 5 копеек. Сообщение об ошибке: "sketch_sep15a.ino:15:28: error: invalid conversion from 'const char*' to 'char' [-fpermissive]"
можно перевести и так: "Инвалид пытается превратить указатель на константу в символьную переменную" .. и эта ошибка практически одинакова как в первой цитате, так и во второй. Вам уже несколько раз отписали, что такое преобразование типов чревато последствиями.. в таком виде и отсутствии понимания - особенно. Что и "беспокоит" компилятор. :)
Указатель на константу - const char* - это НЕИЗМЕННЫЙ указатель. А у вас параметр функции объявлен как char* -- то есть ИЗМЕНЯЕМЫЙ. Вот компилятор и "опасается за инвалида". :) Исправить ситуацию можно объявив параметр константным указателем, типа так:
В этом случае, вы объявляете компилятору, что функция НЕ СОБИРАЕТСЯ изменять содержимое и она может принимать как const char*, то есть "строки во флеш"..
Жалко что подобные хитрости не описываются для новичков, вот что у меня получилось, а если учесть что в программах бывает очень много текста, то получится очень существенная экономия ОЗУ. Недавно я изучал программирование на андроиде и там все текстовые сообщения и названия были вынесены в отдельные переменные, что помогало легко изменять текст сразу в нескольких местах и упрощало перевод с одного языка на другой. Тут я подумал что это будет лишнем, но не угадал :)
Ещё раз всем спасибо за помощь, раньше я думал что улучшить было в этом месте не чего, а оказывается тонкостей ещё хуча. :)
#include <avr/pgmspace.h>
#include <Wire.h>
#include <LiquidCrystal_I2C.h>
LiquidCrystal_I2C lcd(0x27,16,2);
const char message[ ] PROGMEM = "arduino";
void setup() {
// put your setup code here, to run once:
Serial.begin(9600);
lcd.init(); // Инициализируем дисплей
lcd.backlight(); // Включаем подсветку экрана
/* lcd.setCursor(0, 0);
lcd.print("arduino"); // заменяем на printMessage()
*/
printMessage(0, 0, message);
}
void loop() {
}
void printMessage(byte Xpos, byte Ypos, const char *text){
lcd.setCursor(Xpos, Ypos);
char myChar;
byte len = strlen_P(text);
for (byte k = 0; k < len; k++){
myChar = pgm_read_byte_near(text + k);
lcd.print(myChar);
}
}
// Без использования PROGMEM:
// Global variables use 426 bytes (20%) of dynamic memory, leaving 1 622 bytes for local variables. Maximum is 2 048 bytes.
// С использования PROGMEM:
// Global variables use 418 bytes (20%) of dynamic memory, leaving 1 630 bytes for local variables. Maximum is 2 048 bytes.
Это сколько же "всяких переменных" надо объявить, чтобы израсходовать более полутора килобайт памяти...
Могу предположить, что Ваши переменные, которые забивают память, - это текстовые константы. Если так, их можно оставить в PROGMEM, не копируя в оперативную память.
Sketch uses 59 462 bytes (23%) of program storage space. Maximum is 253 952 bytes.
Global variables use 3 120 bytes (38%) of dynamic memory, leaving 5 072 bytes for local variables. Maximum is 8 192 bytes.
)))
ДА это как минимум МЕГА 2560, но принципиально в данном случае нужно в нано уместится :)
с появлением PROGMEM в моей программе начались какие то глупости:
Привожу куски кода:
const PROGMEM int voltageIntervals[6] = {950, 870, 815, 780, 680, 350}; int FindPressedButton(int _valueVoltageButton){ static int value; for (int i = 0; i < 6; i++) { if (_valueVoltageButton > voltageIntervals[i]){ Serial.print("i - "); Serial.println(i); Serial.print("_valueVoltageButton - "); Serial.println(_valueVoltageButton); Serial.print("voltageIntervals[i] - "); Serial.println(voltageIntervals[i]); if (value == i){ count++; if (count == 3) { count = 0; return i+1; } return 0; } else { value = i; Serial.print("value - "); Serial.println(value); return 0; } } } return 0; }на выходе получаю:
Welcome()
i - 4
_valueVoltageButton - 859
voltageIntervals[i] - 65
value - 4
pressedButton - 0
i - 4
_valueVoltageButton - 844
voltageIntervals[i] - 65
pressedButton - 0
i - 4
_valueVoltageButton - 844
voltageIntervals[i] - 65
pressedButton - 0
i - 4
_valueVoltageButton - 845
voltageIntervals[i] - 65
pressedButton - 5
Откуда voltageIntervals[i] - 65 ???
Убираю PROGMEM из строки (int voltageIntervals[6] = {950, 870, 815, 780, 680, 350};) :
i - 2
_valueVoltageButton - 858
voltageIntervals[i] - 815
pressedButton - 0
i - 2
_valueVoltageButton - 858
voltageIntervals[i] - 815
pressedButton - 0
i - 2
_valueVoltageButton - 859
voltageIntervals[i] - 815
pressedButton - 3
По ходу появляются ошибки в ОЗУ, в чём проблема?
kisoft, вы попонтоваться или посоветовать что то полезное?
Цитирую своё сообщение:
"
inttimeLightTimer[4][2][2][2] = {};// удалить позжеэто звучит гордо!Наверное я убогий, никогда такие массивы не были нужны. 4 уровня - это круто!
Удалить позже статчиеский массив это "прикольно|."
Я удивился 4 уровневому массиву. В чем тут понты?
Я удивился комментарию "удалить позже". В чем тут понты? Научите, как можно удалить статический массив? Буду очень благодарен.
Не нравится? Ок, запишу в черный список, постараюсь больше не беспокоить.
Научите, как можно удалить статический массив? Буду очень благодарен.
я тебя научу - выделяешь в текстовом редакторе строку массива и нажимаешь клавишу "Delete".
всё. с тебя 1$
Научите, как можно удалить статический массив? Буду очень благодарен.
я тебя научу - выделяешь в текстовом редакторе строку массива и нажимаешь клавишу "Delete".
всё. с тебя 1$
Перечислил на карту
kisoft, ну вы крайне обидчивый :)
Такой массив был для меня удобен в плане обращения к нему
int timeLightTimer[4][2][2][2] = {}; // удалить позже //byte timeLightTimer[selectedLight][selectedLightTimerInterval][selectedLightTimerOnOff][selectedTimerHM];первая строка - цвет света - синий, красный, белый, зелёный
вторая строка - интервал - первый, второй
третья строка -действие - включение, выключение
четвёртая строка - время - часы, минут.
В таком виде массив был для меня более читабелен, чем
inttimeLightTimer[32], так я вижу сколько цветов, сколько интервалов времени.А про удалить, тут полностью прав Клапауций 234, нужно было просто удалить клавишей Delete.
Вместо этого массива я перешёл на класс, и теперь вся эта информация будет у меня хранится в созданных объектах.
Просто библиотеку я уже написал, а вот сам проект на этот класс не перевёл, поэтому в коде есть строки со сторым исполнением.
Обидчивый? Возможно. Хотя, честно говоря мне по барабану, нет так нет. Не нужна помощь - не вопрос.
PROGMEM константы нужно считывать, увы, это не АРМ, например, PROGMEM
kisoft, спасибо.
Как то я сразу на заметил "pgm_read_word(data)";
Подскажите только пожалуйста как мне обращаться к данным этого массива через pgm_read_word(data);
const PROGMEM byte matrixMenu[45][5] = { // {Номер меню, родительское меню, дочернее меню, Х_курсор, Y_курсор}; menu {0, 0, 1, 0, 0}, {0, 0, 1, 0, 1}, {1, 0, 2, 0, 0}, {2, 1, 3, 0, 0}, {2, 1, 6, 0, 1}, {2, 1, 14, 10, 0}, {2, 1, 17, 10, 1}, {3, 2, 4, 0, 0}, {3, 2, 4, 0, 1}, {3, 2, 4, 8, 0}, {3, 2, 4, 8, 1}, {4, 3, 5, 0, 0}, {4, 3, 5, 0, 1}, {5, 4, 5, 0, 0}, {6, 2, 7, 0, 0}, {6, 2, 7, 0, 1}, {6, 2, 7, 8, 0}, {6, 2, 7, 8, 1}, {7, 6, 9, 0, 1}, {7, 6, 8, 8, 0}, {7, 6, 10, 8, 1}, {8, 7, 8, 0, 0}, {9, 7, 9, 6, 0}, {9, 7, 9, 6, 1}, {10, 7, 11, 0, 0}, {10, 7, 11, 0, 1}, {11, 10, 12, 6, 0}, {11, 10, 12, 6, 1}, {12, 11, 13, 6, 0}, {12, 11, 13, 6, 1}, {13, 12, 13, 6, 0}, {13, 12, 13, 6, 1}, {14, 2, 15, 0, 0}, {14, 2, 15, 0, 1}, {14, 2, 18, 8, 0}, {14, 2, 18, 8, 1}, {15, 14, 16, 0, 0}, {15, 14, 16, 0, 1}, {15, 14, 16, 8, 0}, {15, 14, 16, 8, 1}, {16, 15, 16, 6, 0}, {16, 15, 16, 6, 1}, {17, 2, 17, 6, 0}, {17, 2, 17, 6, 1}, {18, 14, 18, 0, 0} };matrixMenu[45][3] это pgm_read_word(matrixMenu+((45-1)*5 + 3)), так?
Почему word, массив байтов, читать нужно байты? pgm_read_byte?
И откуда взялся matrix[45][3] - он за пределами массива. Тогда уж matrix[44][3] и вычитать из индекса не нужно.
Можно еще так сделать: pgm_read_byte(&matrix[44][3]); Но это я не проверял, хотя, в принципе должно работать, короче нужно проверять.
Пытаюсь сэкономить память:
в итоге получаю:
error: statement-expressions are not allowed outside functions nor in template-argument lists
Получается нельзя использовать константы PROGMEM при объявлении массивов?
Вот так тоже не работает:
//**************** Button *****************// const PROGMEM byte RELAY_TEMPERATURE1 = 1; const PROGMEM byte RELAY_TEMPERATURE2 = 3; const PROGMEM byte RELAY_FILTER = 4; const PROGMEM byte RELAY_AIR = 5; switch (pressedButton) { case pgm_read_byte(&RELAY_TEMPERATURE1): // 1 break; case pgm_read_byte(&RELAY_TEMPERATURE2): // 3 break; case pgm_read_byte(&RELAY_FILTER): //4 break; case pgm_read_byte(&RELAY_AIR): //5 break; }Так просто нельзя делать или это как то обходится?
Получается нельзя использовать константы PROGMEM при объявлении массивов?
Нет, не получается. Константы можно, а вот вызовы функций - нельзя.
orcsin, объясните, как именно Вы пытаетесь сэкономить память? И при чем здесь PROGMEM?
Вот так тоже не работает:
...
Так просто нельзя делать или это как то обходится?
orcsin,
Вы, похоже, не понимаете. что делаете, а пытаетесь методом тыка поймать комбинацию при которой хотя бы скомпилируется.
Ну, вот что Вы написали:
Вы понимаете. что означает слово const? Это означает КОНСТАНТА. Ну, а если она конастанта, то нафига ж Вы её менять пытаетесь?
Константы не меняются в процессе работы программы (а если и меняются, то не так и делать этого в порядочной программе не стоит).
Кроме того, Вы знаете, что должно идти после слова case? Константа интегрального типа, а Вы что туда пихаете?
Почитайте книжку по языку (я Вам уже советовал это в посте №9). Без этого Вы так и будете как слепой котёнок тыкаться, авось компилятор схавает. Но он ведь может схавать, но скомпилировать совсем не тот код, которого Вы ожидаете.
orcsin, объясните, как именно Вы пытаетесь сэкономить память? И при чем здесь PROGMEM?
В данном случае у меня пролема с ОЗУ. Её осталось мало. Выше мне подсказали PROGMEM, благодаря которой можно часть переменых переместить во флешь память. Ну на сколько я это понял.
Вот и пробую сделать именно это.
Выше мне подсказали PROGMEM, благодаря которой можно часть переменых переместить во флешь память.
ну, ок - ты что-то где-то прочитал.
а, как ты собрался менять переменные, которые возможно изменить, переписав флеш?
*так, чисто практический интерес имею - хочу писать флеш из исполняемого кода.
orcsin,
Вы, похоже, не понимаете. что делаете, а пытаетесь методом тыка поймать комбинацию при которой хотя бы скомпилируется.
Ну, вот что Вы написали:
Вы понимаете. что означает слово const? Это означает КОНСТАНТА. Ну, а если она конастанта, то нафига ж Вы её менять пытаетесь?
Почитайте книжку по языку (я Вам уже советовал это в посте №9). Без этого Вы так и будете как слепой котёнок тыкаться, авось компилятор схавает. Но он ведь может схавать, но скомпилировать совсем не тот код, которого Вы ожидаете.
1. Да не пытаюсь вроде осозновать то что пишу :)
2. Я вроде не пытаюсь изменить константу, а только вызываю её значение через
Или я что то не понимаю?
Несколько книг я прочёл, много дало, но видимо там не всё есть с чем приходится сталкиваться. Если посоветуете какую то конкретную книгу, буду очень благодарен. Я про классы прочёл несколько книг, и только в 5ой было написано так, что хоть как то стало понятно.
И про case,
в этих двух строках же вроде один и тот же тип указан, просто один займёт место в ОЗУ, а другой нет. Или я опять что то упустил? На сколько я понял то PROGMEM используется для этого, что бы освободить ОЗУ.
Выше мне подсказали PROGMEM, благодаря которой можно часть переменых переместить во флешь память.
ну, ок - ты что-то где-то прочитал.
а, как ты собрался менять переменные, которые возможно изменить, переписав флеш?
*так, чисто практический интерес имею - хочу писать флеш из исполняемого кода.
Возможно я не понял ответа, но я переношу в PROGMEM только те переменные, которые не собираюсь менять на протяжении всей программы. Тоесть только константы.
2. Я вроде не пытаюсь изменить константу, а только вызываю её значение
Понятия "вызывать значение" нет. Вы пытаетесь присвоеить ей значение, а это и есть поменять её. Она у Вас при описании была 1, а Вы пытаетесь туда что-то другое запихать.
И про case,
в этих двух строках же вроде один и тот же тип указан, просто один займёт место в ОЗУ, а другой нет. Или я опять что то упустил? На сколько я понял то PROGMEM используется для этого, что бы освободить ОЗУ.
Ни в том ни в другом случае RELAY_TEMPERATURE1 не будет занимать ОЗУ. Но и поменять её нельзя, т.к. костанта. Вот Вы сказали, что она 1 - так она 1 и будет всегда.
Здравствуйте, помогите разобраться в следующей ситуации, не много не хватает понимания походу.
#include <avr/pgmspace.h> #include <Wire.h> #include <LiquidCrystal_I2C.h> LiquidCrystal_I2C lcd(0x27,16,2); const char message[ ] PROGMEM = "arduino"; const char message2[ ] PROGMEM = "hello"; // void setup() { // put your setup code here, to run once: Serial.begin(9600); lcd.init(); // Инициализируем дисплей lcd.backlight(); // Включаем подсветку экрана printMessage(0, 0, message); // lcd.setCursor(0, 0); // lcd.println(message); } void loop() { // put your main code here, to run repeatedly: } void printMessage(byte Xpos, byte Ypos, char *text){ lcd.setCursor(Xpos, Ypos); char myChar; byte len = strlen_P(text); for (byte k = 0; k < len; k++){ myChar = pgm_read_byte_near(text + k); lcd.print(myChar); } }Функию printMessage хочу сделать универсальную, что бы ей можно было скармливать любую текстовую константу.
Экономия использования PROGMEM очень заметно, для сообщения "arduino" - экономия ОЗУ - 8 байт.
Но выдаёте ошибку:
sketch_sep15a.ino: In function 'void setup()':
sketch_sep15a.ino:15:28: error: invalid conversion from 'const char*' to 'char*' [-fpermissive]
sketch_sep15a.ino:8:6: error: initializing argument 3 of 'void printMessage(byte, byte, char*)' [-fpermissive]
Ошибка компиляции.
Убираю * -
void printMessage(byte Xpos, byte Ypos, char text){получаю обратную ошибку:
sketch_sep15a.ino: In function 'void setup()':
sketch_sep15a.ino:15:28: error: invalid conversion from 'const char*' to 'char' [-fpermissive]
sketch_sep15a.ino:8:6: error: initializing argument 3 of 'void printMessage(byte, byte, char)' [-fpermissive]
sketch_sep15a.ino: In function 'void printMessage(byte, byte, char)':
sketch_sep15a.ino:28:26: error: invalid conversion from 'char' to 'const char*' [-fpermissive]
In file included from sketch_sep15a.ino:1:0:
c:\program files (x86)\arduino\hardware\tools\avr\avr\include\avr\pgmspace.h:1185:22: error: initializing argument 1 of 'size_t strlen_P(const char*)' [-fpermissive]
static inline size_t strlen_P(const char *s) {
^
Ошибка компиляции.
Помогите это исправить.
Давайте, тоже приложу свои 5 копеек. Сообщение об ошибке: "sketch_sep15a.ino:15:28: error: invalid conversion from 'const char*' to 'char' [-fpermissive]"
можно перевести и так: "Инвалид пытается превратить указатель на константу в символьную переменную" .. и эта ошибка практически одинакова как в первой цитате, так и во второй. Вам уже несколько раз отписали, что такое преобразование типов чревато последствиями.. в таком виде и отсутствии понимания - особенно. Что и "беспокоит" компилятор. :)
Указатель на константу - const char* - это НЕИЗМЕННЫЙ указатель. А у вас параметр функции объявлен как char* -- то есть ИЗМЕНЯЕМЫЙ. Вот компилятор и "опасается за инвалида". :) Исправить ситуацию можно объявив параметр константным указателем, типа так:
voidprintMessage(byteXpos,byteYpos,const char*text){В этом случае, вы объявляете компилятору, что функция НЕ СОБИРАЕТСЯ изменять содержимое и она может принимать как const char*, то есть "строки во флеш"..Arhat109-2, большое спасибо, с указателями пока туго получается, нет практики, а без практики - нет понимания.
Жалко что подобные хитрости не описываются для новичков, вот что у меня получилось, а если учесть что в программах бывает очень много текста, то получится очень существенная экономия ОЗУ. Недавно я изучал программирование на андроиде и там все текстовые сообщения и названия были вынесены в отдельные переменные, что помогало легко изменять текст сразу в нескольких местах и упрощало перевод с одного языка на другой. Тут я подумал что это будет лишнем, но не угадал :)
Ещё раз всем спасибо за помощь, раньше я думал что улучшить было в этом месте не чего, а оказывается тонкостей ещё хуча. :)
#include <avr/pgmspace.h> #include <Wire.h> #include <LiquidCrystal_I2C.h> LiquidCrystal_I2C lcd(0x27,16,2); const char message[ ] PROGMEM = "arduino"; void setup() { // put your setup code here, to run once: Serial.begin(9600); lcd.init(); // Инициализируем дисплей lcd.backlight(); // Включаем подсветку экрана /* lcd.setCursor(0, 0); lcd.print("arduino"); // заменяем на printMessage() */ printMessage(0, 0, message); } void loop() { } void printMessage(byte Xpos, byte Ypos, const char *text){ lcd.setCursor(Xpos, Ypos); char myChar; byte len = strlen_P(text); for (byte k = 0; k < len; k++){ myChar = pgm_read_byte_near(text + k); lcd.print(myChar); } } // Без использования PROGMEM: // Global variables use 426 bytes (20%) of dynamic memory, leaving 1 622 bytes for local variables. Maximum is 2 048 bytes. // С использования PROGMEM: // Global variables use 418 bytes (20%) of dynamic memory, leaving 1 630 bytes for local variables. Maximum is 2 048 bytes.