Запись и чтение EEPROM переменных типа float, unsigned long, long, unsigned int, int
- Войдите на сайт для отправки комментариев
Сб, 16/05/2015 - 17:15
Функции чтения и записи EEPROM для разных типов переменных:
// чтение float EEPROM_float_read(int addr) { byte raw[4]; for(byte i = 0; i < 4; i++) raw[i] = EEPROM.read(addr+i); float &num = (float&)raw; return num; } // запись void EEPROM_float_write(int addr, float num) { byte raw[4]; (float&)raw = num; for(byte i = 0; i < 4; i++) EEPROM.write(addr+i, raw[i]); }
// чтение unsigned long EEPROM_ulong_read(int addr) { byte raw[4]; for(byte i = 0; i < 4; i++) raw[i] = EEPROM.read(addr+i); unsigned long &num = (unsigned long&)raw; return num; } // запись void EEPROM_ulong_write(int addr, unsigned long num) { byte raw[4]; (unsigned long&)raw = num; for(byte i = 0; i < 4; i++) EEPROM.write(addr+i, raw[i]); }
// чтение long EEPROM_long_read(int addr) { byte raw[4]; for(byte i = 0; i < 4; i++) raw[i] = EEPROM.read(addr+i); long &num = (long&)raw; return num; } // запись void EEPROM_long_write(int addr, long num) { byte raw[4]; (long&)raw = num; for(byte i = 0; i < 4; i++) EEPROM.write(addr+i, raw[i]); }
// чтение unsigned int EEPROM_uint_read(int addr) { byte raw[2]; for(byte i = 0; i < 2; i++) raw[i] = EEPROM.read(addr+i); unsigned int &num = (unsigned int&)raw; return num; } // запись void EEPROM_uint_write(int addr, unsigned int num) { byte raw[2]; (unsigned int&)raw = num; for(byte i = 0; i < 2; i++) EEPROM.write(addr+i, raw[i]); }
int:
// чтение int EEPROM_int_read(int addr) { byte raw[2]; for(byte i = 0; i < 2; i++) raw[i] = EEPROM.read(addr+i); int &num = (int&)raw; return num; } // запись void EEPROM_int_write(int addr, int num) { byte raw[2]; (int&)raw = num; for(byte i = 0; i < 2; i++) EEPROM.write(addr+i, raw[i]); }
Пример использования:
#include <EEPROM.h> void setup() { Serial.begin(9600); EEPROM_float_write(0, 1.2568); float a = EEPROM_float_read(0); Serial.println(a, 4); } void loop(){} // чтение float EEPROM_float_read(int addr) { byte raw[4]; for(byte i = 0; i < 4; i++) raw[i] = EEPROM.read(addr+i); float &num = (float&)raw; return num; } // запись void EEPROM_float_write(int addr, float num) { byte raw[4]; (float&)raw = num; for(byte i = 0; i < 4; i++) EEPROM.write(addr+i, raw[i]); }
При работе с адресами необходимо помнить, что типы float, unsigned long и long занимают в памяти 4 байта, а типы unsigned int и int 2 байта. Пример записи и чтения трех переменных типа float и трех переменных типа int:
EEPROM_float_write(0, 1.2345); // адрес 0 (+4 байта) EEPROM_float_write(4, 2.3456); // адрес 4 (+4 байта) EEPROM_float_write(8, 3.4567); // адрес 8 (+4 байта) // чтение float a = EEPROM_float_read(0); float b = EEPROM_float_read(4); float c = EEPROM_float_read(8); // запись EEPROM_int_write(12, 1000); // адрес 12 (+2 байта) EEPROM_int_write(14, 2000); // адрес 14 (+2 байта) EEPROM_int_write(16, 3000); // адрес 16 (+2 байта) // чтение int d = EEPROM_int_read(12); int e = EEPROM_int_read(14); int f = EEPROM_int_read(16);
Большое спасибо maksim, думаю, многим поможет такая инфа.
Огромный респект ! Все в одном месте. Спасибо!
Спасибо - полезная и нужная информация !
Я вас умоляю. В какую шапку? Конечно ТС систематизировал и разжевал, ему однозначно респект. Но если ленивый новичек сам до этого не дойдет, прочитав базовые статьи по работе с епромом и о размерах данных, то ему и смысла нет помогать. Все равно лентяи будут писать в пересекающиеся блоки и затирать одну переменную другой, хоть ТС и рассказал об этом.
Согласен. Тема горячая :)
Самая горячая тема здесь - тема дипломного/курсового проекта )))
А давайте ее вынесем в шапку ! :)
Я вас умоляю. В какую шапку? Конечно ТС систематизировал и разжевал, ему однозначно респект. Но если ленивый новичек сам до этого не дойдет, прочитав базовые статьи по работе с епромом и о размерах данных, то ему и смысла нет помогать. Все равно лентяи будут писать в пересекающиеся блоки и затирать одну переменную другой, хоть ТС и рассказал об этом.
+100500
Может для того кто уже знает и понятно, если операции с разбивкой/склейкой примерно понятны, то пример использования с float/void мягко выражаясь не очень. Ну нет хорошо расписанных уроков на эту тему, во всех обучалках упор на использование переферии.
Неужели тяжело было в тексте примера вставить пару коментариев? Да и сам пример использования неудачный.
добрый вечер.
Столкнулся с проблемой записи переменной типа float в EEPROM при помощи функции описанной пользователем maksim. Запись положительных чисел проходит нормально, а вот при записи отрицательного числа с запятой, потом считывается не "0,0", а со знаком минус "-0,0". Причем при записи чисел -0,1, -0,2 проблем не возникает, а вот после записи -0,3, -0,4 и т.д....считать или записать в ячейку 0,0 без занка минус не получается:( помогите!!!:)
Спасибо maksim.
Хочу дополнить, если сохраняемое значение неотличается от сохраненного, то и сохранять его не стоит.
Я ввел проверку
Здравствуйте.
Если мы используем 4 байта вместо 1, то для пользователя удобнее чтобы это уже учитывалось в функции. Покажу на примере float.
И спокойно можно использовать EEPROM_float_write(int addr, float num) и EEPROM_float_read(int addr) в массиве, только помнить, что теперь количество возможных записей не 512, а 512/4.
добрый вечер.
Столкнулся с проблемой записи переменной типа float в EEPROM при помощи функции описанной пользователем maksim. Запись положительных чисел проходит нормально, а вот при записи отрицательного числа с запятой, потом считывается не "0,0", а со знаком минус "-0,0". Причем при записи чисел -0,1, -0,2 проблем не возникает, а вот после записи -0,3, -0,4 и т.д....считать или записать в ячейку 0,0 без занка минус не получается:( помогите!!!:)
До конца не уверен, но возможно такое происходит из-за плавающей точки в float. Столкнулся с такой же проблемой при арифметических операциях с маленькими числами (меньше 1, т.е. то, что идет после запятой). При этих самых арифметических действиях float-ы не складываются/отнимаются/перемножаются/делятся ровно тем числом, что вы прописываете. Бывает выскакивает где-то далеко (~0.000000000000000000000000213000022) какая-нибудь единица и вы отнимаете не ровно 0.1, а на самом деле чуть большее число (например 0.100000...001200). Т.е. той точностью, что у вас стоит(одна цифра после запятой) на самом деле float не ограничивается. Отсюда и вылазят -0.0 (а на самом деле например: -0.00000000000...000001002), просто вам не видны остальные цифры.
Выкрутиться можно каким-то макаром каждый раз зануляя хвост, мне было удобнее перевести float в int(переместил на 2 разряда вперед. Мне всего 2 цифры после запятой были нужны) и потом просто делить на 100, чтобы получить обратно float с 2-мя знаками после запятой.
если я правильно помню
printf("%5.3d",x); покажет 5 знаков, и 3 после запятой, остальное отрежет
если я правильно помню
printf("%5.3d",x); покажет 5 знаков, и 3 после запятой, остальное отрежет
Боюсь, что неправильно помните. "d" - это про целые числа.
Коллеги, а вот кто-нибудь может мне объяснить, зачем всё это, когда в стандартной библиотеке EEPROM имеется универсальный функции EEPROM.put и EEPROM.get, которые благополучно запишут и прочитают любой тип данных, хоть структуру?
Приобрел недавно микросхемки памяти EEPROM на 512 килобит. Эту библиотеку можно будет использовать для записи во внешнюю память любого типа данных?
Я не знаю, чем Вы будете писать во внешний EEPROM, но эти две функции можно добавить в любую библиотеку, которая умее читать/писать байт. Посмотрите на них
Коллеги, а вот кто-нибудь может мне объяснить, зачем всё это, когда в стандартной библиотеке EEPROM имеется универсальный функции EEPROM.put и EEPROM.get, которые благополучно запишут и прочитают любой тип данных, хоть структуру?
а кто сидит на более ранних версиях IDE - тем по другому никак)))
а кто сидит на более ранних версиях IDE - тем по другому никак)))
Ну, почему? Написать такой же шаблон и забыть о разных типах. Зачем писать свою функцию для каждого типа-то?
Я не знаю, чем Вы будете писать во внешний EEPROM, .....................
Функции для записи и чтения из EEPROM любого типа данных. Стандартная библиотека не используется.
Всем доброго времени суток!
А может ли кто-то объяснить как работать с FRAM? Точно таким же образом или там есть свои фишки?
Если конкретно, то FRAM такая: FM24W256 (256-Kbit (32 K × 8) Serial (I2C) F-RAM).
Даташит есть здесь: ссылка
Как в нее записывать и считывать из нее, например, название SSID, пароль, как проектировать место для хранения каких типов данных?
Я в этом вопросе нуб, юзал только запись в EEPROM, но вопросов даже там много. Например, если я хочу сохранить в память название сети (SSID), то мне нужно отводить определенную область памяти для этого (32 байта для хранения возможных 32 символов). Название может быть и короче. Можно ли как-то динамически это менять?
Потом надо отводить место для хранения пароля к этой сети. 64 байта для хранения 64 символов.
А как записывать строки произвольной длины и (самое главное) как их оттуда правильно считывать?
И можно ли устанавливать какие-то метки, которые бы говорили, что такая-то длина отведена для хранения такого количества байт: например, в следующих 128 битах находится название сети.
Что делать, если пишет 'EEPROM_int_write' was not declared in this scope
Автору респект.
Готовые функции , без лишней шелухи,это хорошо.
Что делать, если пишет 'EEPROM_int_write' was not declared in this scope
Функцию скопировать пробовал ?
Если есть ссылка на функцию, стало быть и функция должна быть.
вы немного опоздали с благодарностью - эти функции давно не нужны, в стандартном ардуино есть EEPROM.put() для любых типов данных
Что делать, если пишет 'EEPROM_int_write' was not declared in this scope
Вешацца!
всем привет!
у меня нет проблем при работе с ЕЕПРОМ, а всего один вопрос.... я все понимаю что затирать и писать в ячейки это плохо, а как со чтением? губит ли функция чтения ечейку и как часто можно читать ... в общем про чтение ЕЕПРОМ ничего не нашел
Читать можно пока не надоест.
Коллеги, а вот кто-нибудь может мне объяснить, зачем всё это, когда в стандартной библиотеке EEPROM имеется универсальный функции EEPROM.put и EEPROM.get, которые благополучно запишут и прочитают любой тип данных, хоть структуру?
Интересная реплика!!!
Ситуация: имеем скетч радиолюбительского маяка, по сути это строка передаваемая азбукой Морзе, разбор строки позволяет выделить компоненты, а именно - позывной сигнал, координаты...и эти данные необходимо изменять оперативно, а не перепрошивкой нового скетча, напрашивается передача данных в структуру по коммуникационному порту сохранение в EEPROM с последующим использованием, осталось только научиться это делать )))
Не вижу в этом коде работы с eeprom, а потому не понимаю смысла поста. Можете пояснить, что имелось в виду?
напрашивается передача данных в структуру по коммуникационному порту сохранение в EEPROM с последующим использованием, осталось только научиться это делать )))
И как это противоречит реплике Евгения?
Чтобы научиться - надо сесть и научиться. Посмотрите готовые примеры к библиотеке ЕЕПРОМ, там все есть
Не вижу в этом коде работы с eeprom, а потому не понимаю смысла поста. Можете пояснить, что имелось в виду?
всё очень просто, может подскажите как собрать строку из структуры, как заполнить структуру из EEPROM понятно, так же и как туда сохранить...
Строка это в моём случае переменная call[]
всё очень просто, может подскажите как собрать строку из структуры
Строка это в моём случае переменная call[]
обьявляете строку call[] достаточного размера и потом strcpy() копируете в нее отдельные поля в нужные позиции
всё очень просто, может подскажите как собрать строку из структуры, как заполнить структуру из EEPROM понятно, так же и как туда сохранить...
на самом деле, сериализация структур, особенно со строками - атнють нетривиальная задача...
Да... это не студентов на собеседованиях валить - надо подумать слегонца ;)
всё очень просто, может подскажите как собрать строку из структуры
А требования к таковой сборке можно определить? С примерами структуры и что должно получиться?
всё очень просто, может подскажите как собрать строку из структуры
А требования к таковой сборке можно определить? С примерами структуры и что должно получиться?
Есть функция
Для работы функции сейчас использую такую строку:
В этой строке есть две переменные подстроки, это позывной сигнал - UA6EM и локатор размещения LN14AE их и думаю сохранять из монитора порта в память и оттуда забирать, споткнулся на типах данных )))
думал сделать так
snprintf(call, sizeof(call),"%s jdet vseh v punkte %s", MyBeacon.call_sign, MyBeacon.loc);
Да... это не студентов на собеседованиях валить - надо подумать слегонца ;)
Какие такие студенты, то были дипломированные специалисты )))
Насчет подумать, это да, сей предмет пока не входил в круг моих понятий
snprintf(call, sizeof(call),"%s jdet vseh v punkte %s", MyBeacon.call_sign, MyBeacon.loc);
там правила однако, два-три раза передается свой позывной с пробелами между, потом текст, потом два три раза локатор тоже с пробелами между, то-есть надо не просто собрать строку, но и чтобы она была char и этот char подсунуть функции )))
там правила однако, два-три раза передается свой позывной с пробелами между, потом текст, потом....
И...? Мысль не закончена.
Если строки фиксированные, их можно и сразу в ROM пхать
А что Вы с этой строкой делать собираетесь? Только отправить, а потом выбросить? Или она ещё для чего-то нужна? По-другому: нужно получить такую строку, отправить и освободить память (надо будет, ещё раз получим), или сохранитьнужно?
И структура, кстати, она должна вечно жить или временно?
От ответов на эти вопросы зависит техника работы с памятью.
Если я правильно понял, что
1) серёдка всегда одинаковая, надо только в начало вставить n раз позывной, а в конец n раз "хвост"
2) строка после отправки нафиг не нужна и память можно освобождать.
То можно, например, вот так (если не усираться на параноидальной экономии времени выполнения)
результат
весь смысл сей бодяги, маяк надо инициализировать после определения координат развёртывания аппаратуры и определения каким позывным будем работать, то есть эти данные получить из серийного порта и записать в EEPROM, чтобы при отключении питания не надо было снова вносить корректные данные, при включении питания получаем строку из EEPROM её и подсовываем функции вывода маяка...
Строка должна быть актуальна всегда, вплоть до ввода новых значений...
Как-то так...
Можно конечно не парится а ставить на свой компьютер IDE и ей перешивать маяк всякий раз, когда это потребуется, но как-то не кошерно это
Вы говорите в терминах, которых я не понимаю.
То, что я написал подойдёт?
Если строки фиксированные, их можно и сразу в ROM пхать
нет, позывные разные по длине, тут обратное правило чем короче тем круче )))
Вы говорите в терминах, которых я не понимаю.
То, что я написал подойдёт?
Да, только строку надо сохранить и сохранить в EEPROM, при включении оттуда забрать, срок жизни строки - до выключения питания, маяк работает круглосуточно, раз в три минуты передавая этот текст
Сейчас соберу весь скетч, попробую, реализация понятна
весь смысл сей бодяги, маяк надо инициализировать после определения координат развёртывания аппаратуры и определения каким позывным будем работать, то есть эти данные получить из серийного порта и записать в EEPROM, чтобы при отключении питания не надо было снова вносить корректные данные, при включении питания получаем строку из EEPROM её и подсовываем функции вывода маяка...
звучит как ТЗ в разделе "Ищу исполнителя", уж простите. Не вижу ничего сложного, но удивлен, что активному участнику форума надо обьяснять очевидные вещи.
Делите задачу на отдельные части:
1. Прием позывного из Сериал
2. Запись позывного в ЕЕПРОМ
3. Извлечение позывного из ЕЕПРОМ
4. Формирование готовой строки из позывного, места положения и чего там еще
Задачки 1-3 по отдельности разобраны на форуме неоднократно. Задачу 4 только что расписали sadman и Евгений.
А уж скомпоновать из 4 задачек готовый код - это либо сами, либо в упомянутый раздел.
Я понимаю о чем речь, но не понимаю что тут непонятного в двух примерах. Наверное кто-то еще и с Сериала две строчки затрудняется получить...