Максимальный размер массива символов
- Войдите на сайт для отправки комментариев
Привет всем!
Сегодня столкнулся с такой проблемой. Написал скетч для MEGA-2560, в нем используются два массива такого типа:
static char *ruWords[] = {"Один", "Два", ....., "Тридцать один", ""}; static char *enWords[] = {"One", "Two", ....., "Thirty one", ""};
Массивы предназначены для локализации меню и вместо цифр там названия пунктов. В меге все прекрасно работает. Я решил залить этот скетч в Nano v3.0 и возникли проблемы, а именно при адресации к элементам массива ruWords, происходит обращение к фиг знает каким участкам памяти. Такое впечатление, что массив с русскими строками не помещается в памяти. Опытным путем это было подтверждено, я начал добавлять по одному русскому пункту в массив ruWords. Сначала все работало хорошо, но в какой-то момент опять начало лагать, дуинка перезагружалась, либо выводила на экран мусор. В связи с этим возник вопрос, есть ли ограничение на максимальный размер массива, и поможет ли разбиение массива ruWords на несколько массивов меньшего размера?
[...]
В связи с этим возник вопрос, есть ли ограничение на максимальный размер массива, и поможет ли разбиение массива ruWords на несколько массивов меньшего размера?
Есть: смотрим строчки "ОЗУ" у Mega-2560 и у Nano
Не поможет - объем ОЗУ это никоим образом не увеличивает.
Однако, может помочь размещение подобных массивов в программной памяти (предпочтительно) или EEPROM.
Кроме того, может помочь оптимизация массовов - хранение не фраз, как у вас, а только слов, обозначающих единицы и десятки:
и сборка фраз в процессе вывода
Однако, может помочь размещение подобных массивов в программной памяти (предпочтительно) или EEPROM.
Другими словами вам нужно загуглить слово "PROGMEM"
Впрочем, можно и не гуглить, а сразу в доку лезть
Arduino - PROGMEM и мотать вниз на раздел "Arrays of strings". Там есть готовый пример.
Впрочем, всегда можно столько строк набить, что никакой памяти не хватит (особенно с русскими буквами).
Тогда самый крайний вариант - цеплять SD карту и с нее, по мере надобности, подгружать.... правда это может весьма печально сказатся на быстродействии.
Не поможет - объем ОЗУ это никоим образом не увеличивает.
Мой скетч занимает 18кБ, что значительно больше ОЗУ, следовательно скетч грузится в ОЗУ МК по мере необходимости частями? Я так думаю, если разбить один массив на части, то они будут подгружаться и выгружаться в ОЗУ по мере необходимости?
Однако, может помочь размещение подобных массивов в программной памяти (предпочтительно)
Можно подробнее - это что за память?
Кроме того, может помочь оптимизация массовов - хранение не фраз, как у вас, а только слов, обозначающих единицы и десятки:
числа я для примера написал, на самом деле там фразы не поддающиеся оптимизации, я об этом в первом посте писал.
Arduino - PROGMEM и мотать вниз на раздел "Arrays of strings".
О! Видимо то что надо, спасибо буду смотреть, когда попробую отпишусь. Еще вопрос, а у PROGMEM какое ограничение размера?
Мой скетч занимает 18кБ, что значительно больше ОЗУ, следовательно скетч грузится в ОЗУ МК по мере необходимости частями? Я так думаю, если разбить один массив на части, то они будут подгружаться и выгружаться в ОЗУ по мере необходимости?
а у PROGMEM какое ограничение размера?
Для простоты понимания можете такие аналогии провести с PC:
RAM - это "оперативка", а FLASH - это "винчестер" (HDD). Программа на "винте" может занимать сколько угодно (в пределах объема винчестера) и подгружать необходимые данные в память - по мере надобности.
Возвращаясь к ардуине.
Скетч - у вас записывается на FLASH. И там же выполняется. Но переменные, по умолчанию, что-бы иметь возможность их легко менять и легко читать - при старте копируются в RAM (оперативку).
Когда вы помечаете переменную ключевым словом PROGMEM вы говорите компилятору: "а не нужно ее при старте копировать в RAM, я сам скопирую когда она мне понадобится" (ну и, естественно нужно это не забыть сделать). За счет того что вы можете свои строки "подгружать" по одной (или даже "по одному символу"), типа "загрузил-отправил на экран, на это же место загрузил вторую строку - отправил", у вас не будет в RAM одновременно всех строк. Следовательно можно работать с гораздо большим количеством. То которое влезет во флешь (сколько влезет - либо читать доку на плату, либо смотреть при компиляции размер скетча).
Для простоты понимания можете такие аналогии провести с PC:
Ну уж я не совсем тупой, просто с программированием МК недавно завязался и некоторые тонкости не знаю :)
Когда вы помечаете переменную ключевым словом PROGMEM вы говорите компилятору: "а не нужно ее при старте копировать в RAM, я сам скопирую когда она мне понадобится" (ну и, естественно нужно это не забыть сделать).
За разъяснение работы PROGMEM спасибо! Переписал как в примере расписано и все получилось. Правда вылез еще один непонятный косяк, но я его обошел, к сожалению не разобравшись в сути проблемы. Может быть у МК есть глубина передачи массива символов, внутрь функции? Т.е. у меня произошло следущее, была такая реализация:
И видимо пробрасывание переменных st1 и st2 из функции в функцию где-то терялось, в общем нифига не работало. Заработало только когда я в функцию printToScreen стал передавать локализованные строки и дальше этой функции они не уходили. Вот такая у меня осталась непонятка. А еще отлаживать код без real-time debuger очень трудно.
И видимо пробрасывание переменных st1 и st2 из функции в функцию где-то терялось, в общем нифига не работало. Заработало только когда я в функцию printToScreen стал передавать локализованные строки и дальше этой функции они не уходили. Вот такая у меня осталась непонятка. А еще отлаживать код без real-time debuger очень трудно.
Нифига не понятно что у вас нифига не работало.
Проблема по которой создавалась тема решена, всем спасибо! В этой теме не буду больше флудить и мучать ваши мозги.
OK :)
Кстати, есть еще родственный PROGMEM-му макрос. PSTR
Он делает то же самое что и PROGMEM для переменных, только для строк захадкожены в код.
У меня схожая проблема с переполнением ОЗУ. В определенный момент программы нужно передавать крупные массивы байт.
Если я вместо использования PROGMEM. Данные массивы буду инициалицировать не глобально, а локально в функциях.
Как я понимаю время существования локальной переменной только во время выполнения функции, что вполне меня устривает.
Или же при старте ардуины все возможные переменные записываются в ОЗУ и глобальные и локальные.....мне кажется это не так. Разъясните пожалуйста.