очередной раз PROGMEM
- Войдите на сайт для отправки комментариев
Пт, 19/01/2018 - 10:38
Всем бобра!
Замахнулся было на блок управлени аудио усилком с графическим дисплеем. Но память на Про-мини не резиновая. Начал освобождать оперативку, и уперся в хню, которая пока вне пределов моего понимания.
Собсно код:
#include <avr\pgmspace.h> const char str_0[] PROGMEM = "Для выхода - SELECT"; const char str_1[] PROGMEM = "ЗАДЕРЖКА ВКЛЮЧЕНИЯ"; const char str_2[] PROGMEM = "ДО СВИДАНИЯ!"; const char* const text[] PROGMEM = {str_0, str_1, str_2}; void setup() { Serial.begin(115200); while(!Serial); Serial.println("Мы тут"); } void loop() { for (byte i = 0; i<3; i++) softPrint(text[i]); } void softPrint( const char* const st){ char textBuffer[30]; // strcpy_P(textBuffer, (char*)pgm_read_word(st)); strcpy_P(textBuffer, (char*)__LPM_word((uint16_t)(st))); Serial.println(textBuffer); }
Толи я аргумент неправильно в функцию передаю, толи я его принимаю не правильно, но скорее всего я его обрабатываю не верно. Код компилится, и зависает. В сериал печатается только М.
Может кто подскажет как правильно? Здоровый глум и кидание ссылками приветствуются!
Слегка модефицировал :
В итоге вечный перегруз:
Читать до просветления: https://playground.arduino.cc/Main/PROGMEM
Читать до просветления: https://playground.arduino.cc/Main/PROGMEM
pgm_read_word, ну или __LPM_word((uint16_t)(х)), что то же самое, требуют передать адрес. И по всей видимости 47106 - это и есть адрес, который передается первый раз.
Безусловно я где-то косячу, но где - понять не могу.
Плохо читали, видимо. Вопрос: у вас параметр функции какой тип имеет? В нём есть ключевое слово PROGMEM, указывающее, что это адрес в PROGMEM? Вот как ответите на этот вопрос - сразу станет легче ;)
У Вас сами указатели (массив text) тоже сидит в PROGMEM, а Вы используете их в строке 6 как если бы они были в оперативной памяти.
5N62V - небольшой совет. Не кладите массив text[] в PROGMEM. В нем же только ссылки, места они занимают мало. Зато код станет значительно проще и примерно вдвое короче.
У Вас сами указатели (массив text) тоже сидит в PROGMEM, а Вы используете их в строке 6 как если бы они были в оперативной памяти.
Евгений, в строке 6 все нормально. Указатели на PROGMEM -такие же указатели, как любые другие. Их можно сохранить в массиве без вских "оберток". Главное - при доступе к содержимому по этим указателям сообщить компилятору, что это ПРОГМЕМ. Проблема - в процедуре SOftPrint
такой вариант. И никакой буфер для печати не нужен.
У Вас сами указатели (массив text) тоже сидит в PROGMEM, а Вы используете их в строке 6 как если бы они были в оперативной памяти.
такой вариант. И никакой буфер для печати не нужен.
Возможно, я неясно выразился, поскольку другие тоже не поняли.
Вот смотрите. Здесь Ваша программа с минимальными изменениями - она отлично работает, все строки печатаются правильно. Проверяйте. А вот Ваша uint16_t)text[i] - печатается странно.
Посмотрите на строку 24. Сравните с тем, что было у Вас. Думаю, всё поймёте.
Если непонятки останутся - не стесняйтесь, спрашивайте.
Но тут как бы все равно нужно понимание, как сообщить функции, что переданный адрес лежит в ПРОГМЕМ.
https://gist.github.com/sticilface/e54016485fcccd10950e93ddcd4461a3
Если после моего поста в голове не устаканилось как это делать на пальцах, и почему в строке 16 печатается чушь и как её поправить, то я могу пройтись каждой букве, не стесняйтесь.
Если после моего поста в голове не устаканилось как это делать на пальцах, и почему в строке 16 печатается чушь и как её поправить, то я могу пройтись каждой букве, не стесняйтесь.
Ну ок, у меня с элегантными решениями проблема из-за недостатка опыта. Я как понимаю, так и пишу, как чукча. Но интереса ради (знаний для) , как правильно передать в ф-цию указатель на строку из ПРОГМЕМ, на базе моего примера?
Я нашел, что нужно использовать PGM_P, но как его не ставлю, компилятор ругается...
почему в строке 16 печатается чушь и как её поправить, то я могу пройтись каждой букве, не стесняйтесь.
Но интереса ради (знаний для) , как правильно передать в ф-цию указатель на строку из ПРОГМЕМ, на базе моего примера?
Я нашел, что нужно использовать PGM_P, но как его не ставлю, компилятор ругается...
[Вопрос снимается. Ответ в коде: нафига передавать указатель, если как правило строки в ПРОГМЕМ глобальные. Проще , действительно, передавать индекс.
по-моему, вот это как раз чушь. При чем тут глобальность строк? В коде Евгения передается как раз указатель, а не индекс - посмотрите внимательнее.
по русски. вот это
pgm_read_word_near((
int
)(text + index))
отдает слово (адрес), которое прочитало из прогмема по адресу text+index
по-моему, вот это как раз чушь. При чем тут глобальность строк? В коде Евгения передается как раз указатель, а не индекс - посмотрите внимательнее.
Посмотрел. Как я понял - передается индекс, который прибавляется к указателю на массив указателей, и по сути индексирует его. Равзе не так?
Как я понял - передается индекс, который прибавляется к указателю на массив указателей, и по сути индексирует его. Равзе не так?
В любом массиве Си выражение (text +index) - это указатель на элемент text[index]. И не важно, что за массив - глобальный, локальный. статический... и где он лежит - в оперативке или на флеше.
В любом массиве Си выражение (text +index) - это указатель на элемент text[index]. И не важно, что за массив - глобальный, локальный. статический... и где он лежит - в оперативке или на флеше.
text +index - это у нас уже внутри функции, а передали-то мы только index!
text +index - это у нас уже внутри функции, а передали-то мы только index!
тогда вы правы. я думал вы про строку 24
5N62V, понимаете, с указателями в прогмем, это люди просто перешли на более высокий уровень абстракции и запудрили мозги. Давайте снимем пудру и поймём насколько всё просто. Сначала поговорим, а потом я сделаю маленикий пример с передачей в функцию именно "указателя".
Итак, что нужно понимать чётко и не давать запудирь себе мозг: Адрес в прогмем (как и любой другой указатель) это число. Вот это держите в голове всё время.
Дальше. Вот в этой записи
на самом деле написано, что str_0, str_1 и str_2 - это адреса (суть числа) соответствующих строк в прогмем. Заметьте эти адреса по любому глобальны, т.к. сам прогмем глобален.
А вот массив text содержит эти самые адреса. То есть
text[0] - это адрес в прогмем строки "For exit - SELECT" (обозначим его чере А)
a text+0 - это адрес в прогмем адреса А. Т.е. это адрес в прогмем по которому в прогмем хранится адрес строки "For exit - SELECT"
text[1] - это адрес в прогмем строки "Delayed power on" (обозначим его чере B)
a text+1 - это адрес в прогмем адреса B. Т.е. это адрес в прогмем по которому в прогмем хранится адрес строки ""Delayed power on"
Ещё раз - все адреса - это просто числа - номера ячеек прогмем.
Вернёмся к строке 16 в предыдущем примере. Вы там печатаете
Serial
.println((uint16_t)text[i]);
, но ведь text[i] хранится в прогмем! А Вы печатаете нечто, что хранится в RAM по тому же адресу!Теперь, когда Вы понимаете, что text+i - это адрес в прогмем адреса в прогмем i-ой строки, а text[i] - это хранящийся в прогмем адрес в прогмем i-ой троки, Вы можете передавать в Вашу функцию что хотите и как хотите.
1. индекс
2. адрес адреса строки
3. адрес строки
Пример с передачей индекса (почти как было)
Пример с передачей адреса адреса строки
Пример с передачей адреса строки
Как видите, передавать можно всё, что угодно, важно помнить где у Вас адрес чего, что где хранится, и не путаться.
Евгений, епром и прогмем - разные вещи.
И спасибо за "людей, запудривших мозги" :)
Толково Вы, Евгений , расписали! Спасибо Вам за труд! Может стоит в прикреплялку занести. Трудно переоценить полезность понимания работы с ПРОГМЕМ.
ПС. Читаем еепром, понимаем флеш.
И спасибо за "людей, запудривших мозги" :)
Евгений, епром и прогмем - разные вещи.
Да, переклинило, сейчас поправлю.
А под "людьми" я не Вас имел в виду, если что. Но если это было обидно - извините, и в мыслях не держал кого-то обижать, извините.
И спасибо за "людей, запудривших мозги" :)
Точно!
А под "людьми" я не Вас имел в виду, если что. Но если это было обидно - извините, и в мыслях не держал кого-то обижать, извините.
та не, я не обиделся, там же смайл :)
Del.
Доброй ночи. Работает код следующим образом: в монитор порта отправляется цифра( в идеале думаю ограничить 0 - 5) и из массива содержащего количество строк и сами строки, записанные в PROGMEM, выводится в порт ссответствующая числу строка.
Возможно ли упростить данный код в замене двумерного массива символов(буфера) на более простой одномерный?
И вообще насколько грамотно написан код, взял чужой, сделал с PROGMEM. Дайте совет?
Вы тут массив используете, как временный буфер в 10 байт. Так что да, упростить и можно и нужно.
Подскажите каким способом если не сложно? Полностью отказаться от буфера?
Ну, как каким... Возьмите один char[10], а не шесть штук.
Что не то вышло... в мониторе ерунда
Понял что все усложняю, сделаю теперпь как мне ЕвгенийП подсказал в#24. Ему отдельная благодарность
ПС
И в итоге
Кстати, в тему о прогмем: давече пробовал разместить двумерный массив данных в прогмем, на 2 кбайта. Разместить-то разместил, а вот с вычитывание обычными средствами , я имею ввиду обычной индексацией двумерных массивов, были проблемы. Решилось размещением одномерного массива, а вычитыванием как двумерного.
Странно это. Так бывает когда расположение перепутано (по строкам или по столбцам). Чтобы не путаться, писать и читать нужно всегда, как одномерный, а пользовать как "что угодно". На то и указатели.
Странно это. Так бывает когда расположение перепутано (по строкам или по столбцам). Чтобы не путаться, писать и читать нужно всегда, как одномерный, а пользовать как "что угодно". На то и указатели.
Видать, не все. По-любому надо заводить указатель на байт, который смотрит на начало массива и писать туда всё по sizeof. Читать также. Тогда никуда не денется.
Здравствуйте. ЕвгенийП, форумчане может вы мне подскажите, все не было времени но сегодня решился повозиться с кодом. Подскажите, допустим объявляю структуру station в коде
Работаю с сериалом .В сериал посылаю цифру пускай 0 - соответствие строке string_0. Хотелось бы в функции function сделать вызов не только строки но и элемента структуры. Для цифры 0 этот элемент reflow.steps. Проще говоря каждой отправленной цифре идет в соответствие выводимая строка и элемнт структуры
PS Функции однозначно хочу передавать только один параметр
Алгоритм сводится только к тому чтобы 1) вычислить номер текущего элемента структуры, 2) его же как параметр передавать в функцию. 3) А далее в функции по номеру уже вычислять элемент ми отправлять его в порт
Но с 1 и не пойму
А чем плохо просто в лоб ?
Можно и в лоб НО
признайте это же бесполезный расход памяти и ненужный рост кода. В примере таких вызовов 5, в моем коде 10, а если будет 20
Да и учиться языку Си тоже нужно...
Во первых, не признаю, расход памяти там настолько копеечный, что говорить неочем. А во-вторых, если Вы хотите учиться, так Вы не с того начали. Начните не с языка, а со стуктур данных и построения алгоритмов - это общие вещи, которые от языка не зависят. Та структура. которую Вы сделали - неоднородна, а потому систематически её обрабатывать трудно, если не сказать вообще невозможно. Если хотите регулярную обрабтку, делайте однородную структуру. Вот как массив - Вы легко работаете с ним по индексу. Но ведь в массиве все элементы имеют один и тот же тип. А в Вашей структуре - разные.
Может быть предложите другой способ (не структурой но и не ваш) . Буду вам очень благодарен, хочется доделать
Та структура. которую Вы сделали - неоднородна, а потому систематически её обрабатывать трудно, если не сказать вообще невозможно. Если хотите регулярную обрабтку, делайте однородную структуру. Вот как массив - Вы легко работаете с ним по индексу. Но ведь в массиве все элементы имеют один и тот же тип. А в Вашей структуре - разные.
Да вы правы. Но может я опять все усложняю. Такое ТЗ сделал поскольку часть меню решил сделать так, что нажатием одной кнопки можно было перелистывать страницы(обновлять экран) и на них бы отображалась текущая строкка и переменная. Со строками благодаря вам разобрался а с перемнными пускай даже целыми но разного размера int, byte не могу. Хотя нецелые все же нужны. Если не додумаюсь сделаю все int в ущерб себе, создам массив и закрою тему
Прикинул что достаточно одной переменной double точно - отдельно будет выводиться, другие сделаю int массив. Спасибо, вопрос закрыт
Я правда не понимаю, что Вам нужно. Все нормальные люди в такой ситуации пишут пачку ифов. Если Вы хотите работать как с массивом, Вам нужно ментяь организацию данных. Если Вы хотите спрятать печать и писать её в одном месте, Вам надо что структура сама себя печатала через интерфейс Printable. Чего Вам надо то?
BuonanotteMash. Задачу организации примитивной консоли на Ардуине вы не потяните.