Запись String в EEPROM

Narum
Offline
Зарегистрирован: 03.06.2019

Здравствуйте. Рассчитываю на вашу помощь и подсказку. 
Что хочу сделать: Индивидуальный цифровой ключ пользователя. 
Условие: Длина ключа от 10 до 16 символов. Устанавливается конечным пользователем и запоминается в EEPROM

Итог: Смог все сделать. кроме записи строки в еепром. Пробовал следующим вариантом: 

byte userNumber = 5;
String myString = "1234567890";

void writeEEPROM()
{
   int address = 10;
   EEPROM.put(address, userNumber);
   address += sizeof(byte); 
   EEPROM.put(address, myString)
   address += sizeof(String); 
}

void readEEPROM()
{
   int address = 10;
   EEPROM.get(address, userNumber);
   address += sizeof(byte); 
   EEPROM.get(address, myString)
   address += sizeof(String); 
}

Но ничего не получилось. Решил проверить считывание еепром с помощью Serial.println(); Получил в ответ иероглифы. Подскажите. пожалуйста, как правильно тут сделать запись строки в память. При этом необходимо учитывать длину занимаемого строкой места, т.к. будут и другие записи/обращения к еепром. 

Находил несколько вариантов решения, но почему-то они работали только до перезагрузки устройства. После перезагрузки - снова сбой. 

Спасибо. 
 

mykaida
mykaida аватар
Offline
Зарегистрирован: 12.07.2018

А поискать? На этом форуме данный вопрос возникает с завидной регулярностью. Или влом?

ЕвгенийП
ЕвгенийП аватар
Offline
Зарегистрирован: 25.05.2015

Здесь на форуме эта тем много (от слова МНОГО) раз обсуждалась. Поищите поиском. Сразу скажу, что тип String Вы туда не засунете. Для это нужна определённая квалификация. Если бы она у Вас была, то не было бы этого вопроса. А вот тип char * возможно сумеете, поищите обсуждения здесь на форуме.

rkit
Онлайн
Зарегистрирован: 23.11.2016

string это обертка над char*, и значимой разницы в реализации данной задачи нет. Для особо квалифицированных.

b707
Онлайн
Зарегистрирован: 26.05.2017

rkit пишет:

string это обертка над char*, и значимой разницы в реализации данной задачи нет. Для особо квалифицированных.

для особо квалифицированных нет, а для новичков есть.

 

rkit
Онлайн
Зарегистрирован: 23.11.2016
uint8_t eeprom_puts(uint8_t offset, String str) {
  return eeprom_puts(offset, str.c_string());
}

uint8_t eeprom_puts(uint8_t offset, char const * str) {
   while(*str) {
       EEPROM.put(offset++, *str++);
   }
   return offset;
}

uint8_t eeprom_gets(uint8_t offset, String & str) {
    char buf[64];
    uint8_t offset = eeprom_gets(offset, buf);
    str = String(buf);
    return offset;
}

uint8_t eeprom_gets(uint8_t offset, char * str) {
   uint8_t size = EEPROM.get(offset++);
   while(size--) {
       EEPROM.get(offset++, *str++);
   }
   *str = 0;
   return offset;
}

Как-то так. Не проверял.

Narum
Offline
Зарегистрирован: 03.06.2019

то есть правильно ли я понял, что корректно будет сделать вот так вот: 

 

byte userName = 5;
String myString = "1234567890"

void writeEEPROM()
{
   int address = 10;
   char *newString[] = myString.c_str();

   for (byte i; i<sizeof(newString); i++)
    {
        EEPROM.put(address, newString[i]);
        address +=i;
    }
}

 

Narum
Offline
Зарегистрирован: 03.06.2019

rkit

Спасибо. Попробую разобраться с этим. 

sadman41
Offline
Зарегистрирован: 19.10.2016

Как интересно - кладётся в EEPROM строка без ограничений и проверок на длину, а считывается всего 64 символа. Для поклажи байта  используется цельная функция put() с внутренним циклом вместо коротенькой update(). offset в uint8_t при размерах епрома в полкило даже в устаревшей 168-й меге - какая-то странная экономия ресурса.

Возврат из puts() offset или кол-ва реально записанных символов - вкусовщина, конечно, но последнее логичней, на мой взгляд.

ЕвгенийП
ЕвгенийП аватар
Offline
Зарегистрирован: 25.05.2015

rkit пишет:
Не проверял.
Напрасно. Проверьте, а уж потом выкладывайте в качестве учебного пособия.

ЕвгенийП
ЕвгенийП аватар
Offline
Зарегистрирован: 25.05.2015

Narum пишет:

то есть правильно ли я понял, что корректно будет сделать вот так вот: 

Неправильно. Вы прибавляете i к адресу. А саму по себе i тоже инкрементируете. И что у Вас получится?

Narum
Offline
Зарегистрирован: 03.06.2019

ЕвгенийП пишет:

Неправильно. Вы прибавляете i к адресу. А саму по себе i тоже инкрементируете. И что у Вас получится?


Точно. Затупил.

byte userName = 5;
String myString = "1234567890"

void writeEEPROM()
{
   int address = 10;
   char *newString[] = myString.c_str();

   for (byte i; i<sizeof(newString); i++) 
    {
       EEPROM.put(address, newString[i]);
    }
   address +=sizeof(newString);
  
}

 

А в остальном я был прав? -)) 

rkit
Онлайн
Зарегистрирован: 23.11.2016

sadman41 пишет:

Как интересно - кладётся в EEPROM строка без ограничений и проверок на длину, а считывается всего 64 символа. Для поклажи байта  используется цельная функция put() с внутренним циклом вместо коротенькой update(). offset в uint8_t при размерах епрома в полкило даже в устаревшей 168-й меге - какая-то странная экономия ресурса.

Возврат из puts() offset или кол-ва реально записанных символов - вкусовщина, конечно, но последнее логичней, на мой взгляд.

Я не помню, сколько там еепрома, поэтому честно предупредил, что не проверял. Для ознакомления с принципом этого кода достаточно.

sadman41
Offline
Зарегистрирован: 19.10.2016

rkit пишет:

Для ознакомления с принципом этого кода достаточно.

Как там было у классика... "Хорош позориться" и "ещё и поделить не осилил" - я правильно процитировал?  

rkit
Онлайн
Зарегистрирован: 23.11.2016

Правильно. Разница в том, что я заранее предупредил о возможных ошибках, а не высосал из пальца бред и назвал это типовым решением, лишь бы показаться на каком-то форуме, что я умнее, чем я есть на самом деле. Ошибаться можно. Врать не надо.  Не переношу этого, уж извините.

qwone
qwone аватар
Offline
Зарегистрирован: 03.07.2016

Вопрос: Почему в библиотеке String есть возможность создания объекта из PROGMEM. Но нет возможности создать это из EEPROM.

Ответ: Решение не так однозначно, и дано на откуп пользователей. Так что никакой классики или неклассики тут  нет.

ПС: Потеряли эту строку 

char EEMEM adrString[16];// зарезервировать 16 байт в EEPROM

 

ЕвгенийП
ЕвгенийП аватар
Offline
Зарегистрирован: 25.05.2015

rkit пишет:

я заранее предупредил о возможных ошибках

Да, лучше было внимательно посмотреть перед публикацией. Это же пример для новичков, а не для "особо квалифицированных". Но, сейчас-то хоть исправьте, а то новички и вправду буду думать, что писать длину строки в начале не обязательно, при чтении она там сама откуда-нибудь возьмётся.

rkit
Онлайн
Зарегистрирован: 23.11.2016
uint16_t eeprom_puts(uint16_t offset, String str) {
  return eeprom_puts(offset, str.c_string());
}

uint16_t eeprom_puts(uint16_t offset, char const * str) {
   EEPROM.put(offset++, strlen(str));
   while(*str) {
       EEPROM.put(offset++, *str++);
   }
   return offset;
}

uint16_t eeprom_gets(uint16_t offset, String & str) {
    char buf[64];
    uint16_t offset = eeprom_gets(offset, buf);
    str = String(buf);
    return offset;
}

uint16_t eeprom_gets(uint16_t offset, char * str) {
   uint16_t size = EEPROM.get(offset++);
   while(size--) {
       EEPROM.get(offset++, *str++);
   }
   *str = 0;
   return offset;
}

Ладно, по просьбам радиослушателей исправил пару ошибок. Всё еще не проверял, правда. Нету у меня сейчас под рукой ничего.

ЕвгенийП
ЕвгенийП аватар
Offline
Зарегистрирован: 25.05.2015

Narum пишет:

А в остальном я был прав? -)) 

Нет.

Запустите это и выведите в монитор значение sizeof(newString). Оно Вас удивит :-)

Кроме того, тут уже писали выше, использование put для вывода одного байта как-то избыточно. Может быть оптимизатор и сообразит, но по идее это разбазаривание ресурсов.

Ну, и, неясно с какой целью в 13-ой строке увеличивается локальная переменная, которая тут же будет выброшена и забыта.

Я уж не говорю про точку с запятой в строке №2.

Вы может будете сами запускать, прежде, чем выкладывать?

ЕвгенийП
ЕвгенийП аватар
Offline
Зарегистрирован: 25.05.2015

rkit пишет:

Ладно, по просьбам радиослушателей исправил пару ошибок. 

Спасибо, конечно, но, как говорил В.С. Высоцкий: "Двух негодяев вздёрнули на рее, да мало - нужно было четверых". В общем, ошибок там по-прежнему полно.

astwo
Offline
Зарегистрирован: 10.07.2019

Высоцкий поэт, а не капитан пиратского судна. Если много будет вешать, то команды не останется. Так и здесь. Разумеется есть и будут ошибки, как тактические, так и стратегические.

Ворота
Ворота аватар
Offline
Зарегистрирован: 10.01.2016

qwone пишет:

Вопрос: Почему в библиотеке String есть возможность создания объекта из PROGMEM. Но нет возможности создать это из EEPROM.

Согласен с

qwone пишет:

Ответ: Решение не так однозначно, и дано на откуп пользователей. Так что никакой классики или неклассики тут  нет.

Чуток дополню для особо квалифицированных, которым «всё легко, только не компилируется».

Это очень непросто сделать.

Ну, вот допустим, кто-то решил это делать. Понятное дело, что грамотный человек будет это делать не так, как здесь предложено, а через наследование от класса String, c добавлением конструктора «из eeprom» и метода сохранения «в зад». Но дело-то не в этом.

Первая проблема – как узнать, что там что-то есть? Вот, типа, первый запуск, eeprom чистый, как это узнать? Писать туда вместе со строкой специальный дескриптор по которому потом и определять наличие или отсутствие строки? Это всегда удобно и оправданно?

Вторая проблема – надо сохранять, а длина увеличилась. Можно сохранять? Или что-то другое потрёшь?

И таких проблем там ещё полвагона.

Всё это легко и естественно решается при написании конкретного кода в конкретной задаче, но становится проблемой для универсального решения. Поэтому хорошего, оптимального и применимого на все случаи жизни решения тут просто нет.

sadman41
Offline
Зарегистрирован: 19.10.2016

Радиослушатели всё ещё спрашивают:  с какой целью в eeprom_puts() передаётся по значению экземпляр String, для чего отдельно считать длину строки (имея ниже второй проход по ней) и писать её в ячейку из которой она никогда не считывается. А так же: чему равна size и что произойдёт, если size внезапно окажется этак... 65, например.

Kakmyc
Онлайн
Зарегистрирован: 15.01.2018

ТС, вы задачу изначально решаете через одно место.
Если код состоит из цифр(что мы видим в примере), то String нафиг не нужен. Число спокойно влезет в long

Narum
Offline
Зарегистрирован: 03.06.2019

Kakmyc, хм... Любопытно.  И какой же long Вы посоветуете мне использовать? И если возможно и не затруднит - небольшой пример. Для понимания Вашей мысли. 

sadman41, если вопрос мне, то:
1. Я еще только учусь. Возможно я в чем-то прав или нет. Вот сейчас мне стало интересно записать строку в независимую память. 
2. Кто Вам сказал. что она никогда не считывается? 
3. Относительно size - я ничего пока не могу сказать. Скорее, я пытался комбинировать с примерами из библиотеки. Доберусь в ближайшее время до ардуино - смогу уже более точно проверить: получилось или нет. 
З.Ы. Хотел бы акцентировать внимание: Что я только учусь. Я далек от гуру форума или тех, кто к ним себя причисляет. Посему, сделайте на это поправку. -)) В любом случае, ребята выше дали пинок в нужную сторону и с чем ознакомиться. 

wdrakula
wdrakula аватар
Онлайн
Зарегистрирован: 15.03.2016

Narum пишет:
я только учусь.

Учишься ты или нет и чему - это касается тебя и твоего психотерапевта (или исповедника... от конфессии зависит ;)) ).

Пафос глума над твоим вопросом в ОЧЕНЬ ПРОСТОЙ МЫСЛИ: а как (и на..ера) сохранять в EEPROM объект неизвестного размера???

Если это последний в списке объект то можно реализовать, иначе придется двигать объекты на ним. Или сохранять его, как фиксированный, например 64 ...или 100 байт. Но тогда на..ер нам нужен именно string, а не нормальный юникс-стринг, то есть массив char с нулём на конце ...прстите?

b707
Онлайн
Зарегистрирован: 26.05.2017

Kakmyc пишет:
ТС, вы задачу изначально решаете через одно место. Если код состоит из цифр(что мы видим в примере), то String нафиг не нужен. Число спокойно влезет в long

Поддерживаю

А если не в long - то в long long точно.

Narum
Offline
Зарегистрирован: 03.06.2019

wdrakula пишет:

Учишься ты или нет и чему - это касается тебя и твоего психотерапевта (или исповедника... от конфессии зависит ;)) ).

Пафос глума над твоим вопросом в ОЧЕНЬ ПРОСТОЙ МЫСЛИ: а как (и на..ера) сохранять в EEPROM объект неизвестного размера???

Если это последний в списке объект то можно реализовать, иначе придется двигать объекты на ним. Или сохранять его, как фиксированный, например 64 ...или 100 байт. Но тогда на..ер нам нужен именно string, а не нормальный юникс-стринг, то есть массив char с нулём на конце ...прстите?

Пафос вещь хорошая, если собеседник улавливает то место, где он есть и почему. -)) 
А если ты смотришь и ... ммм... удивленно не понимаешь - это другое. 

Да, к char я и склоняюсь уже. Буду пробовать как-раз с ним теперь. И скорее всего - он не последний обьект списка. Я писал насчет этого в самом верху. Видать народ не рассмотрел "под слоем пыли"

P.S. Спасибо. Отношу себя к пастафариантсву -)) 

qwone
qwone аватар
Offline
Зарегистрирован: 03.07.2016

Причем тут пафос. Тут сплошной Рафшан с Джумшутом и подоконниками, которые вровень со стенкой и немного выступают.

bwn
Offline
Зарегистрирован: 25.08.2014

qwone пишет:

Причем тут пафос. Тут сплошной Рафшан с Джумшутом и подоконниками, которые вровень со стенкой и немного выступают.

Позволю себе, приблизить к оригиналу, там -поколотник

DetSimen
DetSimen аватар
Онлайн
Зарегистрирован: 25.01.2017

b707 пишет:

Kakmyc пишет:
ТС, вы задачу изначально решаете через одно место. Если код состоит из цифр(что мы видим в примере), то String нафиг не нужен. Число спокойно влезет в long

Поддерживаю

А если не в long - то в long long точно.

а 16-значное число в uint64_t влезет?

ЕвгенийП
ЕвгенийП аватар
Offline
Зарегистрирован: 25.05.2015

DetSimen пишет:

а 16-значное число в uint64_t влезет?

Легко. Максимальное (знаковое) число - 922 337 203 685 475 807

ЕвгенийП
ЕвгенийП аватар
Offline
Зарегистрирован: 25.05.2015

Narum пишет:
Отношу себя к пастафариантсву -))
Понятно, так значит это пастафарианство запрещает своим сторонникам наследование классов с расширением функциональности. А я-то думал, что там за религия такая. :-)

Narum
Offline
Зарегистрирован: 03.06.2019

ЕвгенийП, а не подскажите еще. В чем разница между CNP и TRF? И какие их особенности? 
 

sadman41
Offline
Зарегистрирован: 19.10.2016

Narum пишет:

sadman41, если вопрос мне, то:

Не Вам.

ЕвгенийП
ЕвгенийП аватар
Offline
Зарегистрирован: 25.05.2015

Narum пишет:

ЕвгенийП, а не подскажите еще. В чем разница между CNP и TRF? И какие их особенности? 
 

Нет, не подскажу, ибо впервые слышу такие аббревиатуры.

Narum
Offline
Зарегистрирован: 03.06.2019

ЕвгенийП пишет:

Narum пишет:

ЕвгенийП, а не подскажите еще. В чем разница между CNP и TRF? И какие их особенности? 
 

Нет, не подскажу, ибо впервые слышу такие аббревиатуры.

 

А для меня это просто. Я слышу их каждый день. Возможно так же, как и вы "слышите" и разбираетесь в классах + их наследованиях. Все же Ардуино - использует упрощенный язык. и не во всех уроках упоминается о том. что вы сказали. 
 

DetSimen
DetSimen аватар
Онлайн
Зарегистрирован: 25.01.2017

Narum пишет:

Все же Ардуино - использует упрощенный язык

Нет. 

ЕвгенийП
ЕвгенийП аватар
Offline
Зарегистрирован: 25.05.2015

Narum пишет:

Все же Ардуино - использует упрощенный язык.

Это Вам кто сказал? Плюньте в рожу - в Ардуино используется абсолютно полный язык, ничем не отличающийся от языка, используемого в любом другом месте.

Но в целом Вашу позицию я понял. Знаете в чём между нами разница? То, что мы умеем - мы делаем оба, а вот когда не умеем: я либо вызываю специалиста и плачу ему, либо, если хочу научиться сам, беру кучу литературы и начиная с простейших вещей - упражнений, потихоньку учусь, никуда не торопясь. Вы же пытаетесь делать с наскоку сразу сложные вещи (то, что Вам реально понадобилось), не потрудившись изучить даже самые основы. Похоже, Вы пали жертвой навязчивой рекламы производителя, утверждающего, что с ардуино справится любая беременная доярка. Да, справится - сможет помигать светодиодом, может быть даже розовым. Но Вам-то хочется чего-то другого. А тут учиться надо.

Narum
Offline
Зарегистрирован: 03.06.2019

ЕвгенийП пишет:

чего-то другого. А тут учиться надо.

Никто ведь не против учиться. Но вместо кучи сообщений - достаточно было б кому-то написать: "почитай о ... Вот там ты сможешь найти ответ". Или: "Так сделать нельзя потому, что..." 
Ладно. Хайп со своей стороны закрываю -)) Спасибо тем, кто старался помочь в этой теме 

ЕвгенийП
ЕвгенийП аватар
Offline
Зарегистрирован: 25.05.2015

Narum пишет:
Но вместо кучи сообщений - достаточно было б...
Когда Вы задавали конкретные вопросы, я Вам конкретно отвечал (например, #10 и #18). Других конкретных вопросов в теме не было. Хотите что-то знать - спрашивайте.

Kakmyc
Онлайн
Зарегистрирован: 15.01.2018

Narum пишет:

Kakmyc, хм... Любопытно.  И какой же long Вы посоветуете мне использовать? И если возможно и не затруднит - небольшой пример. Для понимания Вашей мысли. 

sadman41, если вопрос мне, то:
1. Я еще только учусь. Возможно я в чем-то прав или нет. Вот сейчас мне стало интересно записать строку в независимую память. 
2. Кто Вам сказал. что она никогда не считывается? 
3. Относительно size - я ничего пока не могу сказать. Скорее, я пытался комбинировать с примерами из библиотеки. Доберусь в ближайшее время до ардуино - смогу уже более точно проверить: получилось или нет. 
З.Ы. Хотел бы акцентировать внимание: Что я только учусь. Я далек от гуру форума или тех, кто к ним себя причисляет. Посему, сделайте на это поправку. -)) В любом случае, ребята выше дали пинок в нужную сторону и с чем ознакомиться. 

Обычный long ,тот самый что int32_t.

Ваш код доступа всего лишь число. И если оно попадает в диапазон 0-2 147 483 647, то займет оно в памяти всего 4байта(читай ячейки ЕЕПРОМ).
Ну и код примерно такой:

long myCode;
EEPROM.get(address,myCode);

if(myCode==inputCode){access_granted_func();}

DetSimen
DetSimen аватар
Онлайн
Зарегистрирован: 25.01.2017

Кактус, у него: 

Условие: Длина ключа от 10 до 16 символов. 

Kakmyc
Онлайн
Зарегистрирован: 15.01.2018

Ну long long вроде никто не отменял

wdrakula
wdrakula аватар
Онлайн
Зарегистрирован: 15.03.2016

Narum пишет:

ЕвгенийП, а не подскажите еще. В чем разница между CNP и TRF? И какие их особенности? 
 


ой. в наш притончик телефониста-динозавра занесло!
Женя, для тебя переведу. CNP connection not possible, TFR transfer restricted. Первое сигнал, второе сообщение. Это из жизни подыхающего монстра ОКС7 - системы общеканальной сигнализации на сетях телефонной связи. Поскольку вся сеть голосовой связи тихо умирает, превращаясь в один из IP сервисов, эти сакральные знания важны также, как умение чинить карету. Я эти сети аж проектировал и в связьэкспертизе защищал... кем только не довелось побывать! ;))

DetSimen
DetSimen аватар
Онлайн
Зарегистрирован: 25.01.2017

Kakmyc пишет:
Ну long long вроде никто не отменял

также как int64_t  и  uint64_t 

кста, кто-нить знает, что у gcc, начиная с 4.7  еще есть целые типы из 3х байт. 

__int24 и __uint24 называюца