Запись в EEPROM
- Войдите на сайт для отправки комментариев
Сб, 26/01/2013 - 14:55
Не могу разобраться в старших-младших байтах. Нужно записать число 3000 в память и потом прочитать его - покажите пожалуйста примерчик как это сделать.
Вначале решите задачу просто "3000 разобрать/собрать" в две байтовые локальные переменные. А потом будете заморчаватся как эти две переменные в EEPROM сохранить (я же так понял "сохранить один байт" уже проблем не вызывает).
Разобрать:
http://arduino.cc/en/Reference/LowByte
http://arduino.cc/en/Reference/HighByte
Собрать:
или
http://arduino.cc/en/Reference/WordCast
void setup(){ Serial.begin(57600); int value=3000; // разбираем byte hi=highByte(value); byte low=lowByte(value); // тут мы эти hi,low можем сохраить, прочитать из eePROM int value2=(hi<<8) | low; // собираем как "настоящие программеры" int value3=word(hi,low); // или собираем как "ардуинщики" Serial.println(value); Serial.println(value2); Serial.println(value3); } void loop(){ }Ну или вот разбор "по крутому", без ардуино функций
С сохранением байта проблем нет. По ссылкам я уже смотрел, но там чайнику ничего не понять. Методология как бы понятна - разбиваю число на 2 байта (старший -младший), пишу в память, читаю, собираю. Примеров на С++ найти не смог.
С сохранением байта проблем нет. По ссылкам я уже смотрел, но там чайнику ничего не понять.
Ну тогда я не знаю что "чайнику понять". Вызов готовой функции это сложно? Ну проще уже просто ничего в природе не бывает. Разве что "сложить переменные". Я понимаю если еще вариант со сдвигами пугает. Но с highByte(),lowByte() и word()? Они же как раз "для чайников" и писались. В "боевом коде" вы их редко встретите (просто не нужны, зная битовые операции и без них не сложно)
Примеров на С++ найти не смог.
Не ну знаю как вы искали. В крайнем случае я вроде уже дал вам примеры. Причем "в двух вариатах" и через функции и через битовые операции.
Спасибо за пример. Буду пробовать.
С сохранением байта проблем нет. По ссылкам я уже смотрел, но там чайнику ничего не понять. Методология как бы понятна - разбиваю число на 2 байта (старший -младший), пишу в память, читаю, собираю. Примеров на С++ найти не смог.
Цитируемый тут "сдвиг на 8 позиций" (>>8) - как раз те самые примеры, ведь Ваши три тысячи представляются в двоичном коде как-то так:
~$ echo "obase=2;3000" | bc
101110111000
Есть два способа.
Первый - с помощью битовых операций, описанный выше.
И второй - работа с памятью:
int val_1 = 3000; int val_2 = 0; // разбиваем byte *x = (byte *)&val_1; byte HighByte = x[1]; byte LowByte = x[0]; // собираем byte xx[] = {LowByte, HighByte}; int *y = (int *)&xx; val_2 = y[0];Пример:
#include <EEPROM.h> void setup() { int val_1 = 3000; int val_2 = 0; // запись в ЕЕПРОМ byte *x = (byte *)&val_1; EEPROM.write(0, x[0]); EEPROM.write(1, x[1]); // чтение из ЕЕПРОМ byte xx[] = {EEPROM.read(0), EEPROM.read(1)}; int *y = (int *)&xx; val_2 = y[0]; // выводим в сериал Serial.begin(9600); Serial.println(val_2); } void loop(){}Ну точнее было-бы назвать это "через указатели". Хотя раз highByte() и lowByte() вызывали проблемы, то не думаю что через указатели будет "понятней".
Но раз пошло "писькомерство" :), то вот еще один вариант, через структуры и объединения.
struct splitted_val { union{ int value; struct { byte hi; byte low; }; byte bytes[2]; // 2 потому что int занимает в памяти два байта }; }; void setup(){ Serial.begin(57600); splitted_val a; // это будем разбирать splitted_val b; // сюда будем собирать byte hi, low; // сюда будем "разбирать" a.value=3000; // установили значение // разбираем собираем первым способом, по именованным поляем hi=a.hi; low=a.low; // сбираем по именованым b.hi=hi; b.low=low; Serial.println(b.value); // вывели что получилось a.value=5000; // возмем для разбора другое значение, что-бы виднее // разбираем через "массив байтов", просто но номерам байтов hi=a.bytes[0]; low=a.bytes[1]; // собираем через массив b.bytes[0]=hi; b.bytes[1]=low; Serial.println(b.value); // вывели что получилось a.value=7000; // возмем для разбора другое значение, что-бы виднее // сделаем сразу "разбор, сбор" миную промеждуточные переменные. Разбор - через массив, сбор - через имена b.hi=a.bytes[0]; b.low=a.bytes[1]; Serial.println(b.value); // вывели что получилось } void loop(){ }Топикстартеру: это "факультативно", если будет интерестно погуглить разобратся как оно работает. Это скорее не пример "нужно обязательно разобратся", а "наш ответ чемберлену/Максиму" ;) "Программерские этюды" :)
А еще нагугливается куча всяких "библиотек-расширений" которые все эти задачи "разобрать/собрать" берут на себя. Сразу умеют int и прочие стандартные типы сохранять.
http://playground.arduino.cc/Code/EEPROMWriteAnything
http://playground.arduino.cc/Code/EepromUtil
http://playground.arduino.cc/Code/EEPROMex
и т.д. и т.п.
А вот есть ли смысл сразу проверять то, что записали? Или оно все равно может позже прочитаться с ошибкой?
А вот есть ли смысл сразу проверять то, что записали? Или оно все равно может позже прочитаться с ошибкой?
Ну, теоретически может. Раз есть ресурс "сколько циклов записи выдерживает" - значить рано или поздно он закончится.
Но IMHO больший смысл имеет чтение ПЕРЕД записью. Если содержимое ячейки и "что собираемся записать" уже совпадает - нечего не делаем. Экономим ресурс EEPROM. А еще, можно, время от времени, менять адреса по котороым пишем. Если данных темного, то ресурс можно увеличить "размазывая" данные по адресному полю с течением времени.
Спасибо за помощ. Записываю и читаю с разделением на 2 байта. Хотел использовать библиотеку EEPROMex , но там косяки. Замены по рекомендации автора библиотеки ничего не дают. Может после модернизации будет работать.
А еще, можно, время от времени, менять адреса по котороым пишем. Если данных темного, то ресурс можно увеличить "размазывая" данные по адресному полю с течением времени.
А как их потом читать? Ведь мы в программе достаточно жестко зашиваем "координаты" тех или иных данных... Если мы их начинаем раскидывать в случайном порядке по всей памяти - надо где-то хранить координаты последих записанных данных. Или увеличить записываемые данные дополнительным полем "дата" и потом, читая все устройство целиком, выбирать максимальное значение даты. Не получится ли это дольше?
А еще, можно, время от времени, менять адреса по котороым пишем. Если данных темного, то ресурс можно увеличить "размазывая" данные по адресному полю с течением времени.
А как их потом читать? Ведь мы в программе достаточно жестко зашиваем "координаты" тех или иных данных... Если мы их начинаем раскидывать в случайном порядке по всей памяти - надо где-то хранить координаты последих записанных данных. Или увеличить записываемые данные дополнительным полем "дата" и потом, читая все устройство целиком, выбирать максимальное значение даты. Не получится ли это дольше?
Ну тут уже на что фантазии хватит и от конкретного проекта зависит. Можно "по понедельникам" в одни адреса, по вторникам - в другие. Можно руками менять раз в месяц. Можно, к примеру, обнулить все EEPROM и записывать "в первую ячейку отличную от нуля". А читать, наоборот "идем с конца пока будет что-то не ноль, это и есть наши данные".
Можно - не делать запись вообще. Записывать только когда "выключаемся". Следить за питанием, поставить какой-нибудь конденсатор который может несколько микросекунд удержать дуину "на плаву". Начала "падать питание" - быстренько сохранили из памяти в EEPROM.
Вообщем это уже простор для вашей фантазии и потребностей. Если вы пишите в EEPROM два раза в день - можно и не морочится.
Читаю одновременно два параметра. Как правильно записать. Получается повторное декларирование.
byte xx[] = {EEPROM.read(25), EEPROM.read(26)}; int *y = (int *)&xx; val1 = y[0]; delay(10); byte xx[] = {EEPROM.read(35), EEPROM.read(36)}; int *y = (int *)&xx; val2 = y[0];Так естественно, просто объедините в функцию...
#include <EEPROM.h> int EEPROM_read(int addr) { byte x[] = {EEPROM.read(addr), EEPROM.read(addr+1)}; int *y = (int *)&x; return y[0]; } void setup() { val1 = EEPROM_read(25); val2 = EEPROM_read(35); }Читаю одновременно два параметра. Как правильно записать. Получается повторное декларирование.
byte xx[] = {EEPROM.read(25), EEPROM.read(26)}; int *y = (int *)&xx; val1 = y[0]; delay(10); byte xx[] = {EEPROM.read(35), EEPROM.read(36)}; int *y = (int *)&xx; val2 = y[0];Сами спросили - сами ответили :) Все верно - повторное деклалирование.
Пользуйтесь уже готовым массиом.
Так естественно, просто объедините в функцию...
А если в функцию, то не проще ли уже
#include <EEPROM.h> int EEPROM_read(int addr) { return word(EEPROM.read(addr),EEPROM.read(addr+1)); } void setup() { val1 = EEPROM_read(25); val2 = EEPROM_read(35); }То же самое сделайте и с записью
#include <EEPROM.h> void EEPROM_write(int addr, int val) { byte *x = (byte *)&val; EEPROM.write(0, x[addr]); EEPROM.write(1, x[addr+1]); } void setup() { EEPROM_write(25, 3000); EEPROM_write(35, 12000); }Так естественно, просто объедините в функцию...
А если в функцию, то не проще ли уже
#include <EEPROM.h> int EEPROM_read(int addr) { return word(EEPROM.read(addr),EEPROM.read(addr+1)); } void setup() { val1 = EEPROM_read(25); val2 = EEPROM_read(35); }В общем дело вкуса...
Доброго здравия. Подскажите если не в тягость: При загрузке нового скетча через IDE очищается eeprom. Геморно потом снова перепрописывать, к то му же каждый час данные меняются. Есть возможность загружать скетчь, чтоб не трогать eeprom?
Необходимо изменить фьюз EESAVE микроконтроллера
Всё гениальное - просто (А. Эйнштейн). Принято, спасибо.
Вот ещё, может кому пригодиться, малёк закоментировал для себя:
#include <EEPROM.h> void setup() { Serial.begin(9600); delay(2000); EEPROMWriteInt(0, 65535); //занимаються ячейки 0 и 1 // 65535 максмальное значение которое можно записать в 2 байта Serial.print("Read the following int at the eeprom address 0: "); Serial.println(EEPROMReadInt(0)); } void loop() { // ничего не делаем } //кушаем аж 2 байта EEPROM void EEPROMWriteInt(int p_address, unsigned int p_value) { byte lowByte = ((p_value >> 0) & 0xFF); byte highByte = ((p_value >> 8) & 0xFF); EEPROM.write(p_address, lowByte); EEPROM.write(p_address + 1, highByte); } // считаем нашы два байта unsigned int EEPROMReadInt(int p_address) { byte lowByte = EEPROM.read(p_address); byte highByte = EEPROM.read(p_address + 1); return ((lowByte << 0) & 0xFF) + ((highByte << 8) & 0xFF00); }Взято отсюда, проверено работает.
е
можете помоч почти с подобным премером?
можете помоч почти с подобным премером?
не, никак, мы токма позыркать тут...
Вначале решите задачу просто "3000 разобрать/собрать" в две байтовые локальные переменные. А потом будете заморчаватся как эти две переменные в EEPROM сохранить (я же так понял "сохранить один байт" уже проблем не вызывает).
Разобрать:
http://arduino.cc/en/Reference/LowByte
http://arduino.cc/en/Reference/HighByte
Собрать:
или
http://arduino.cc/en/Reference/WordCast
можете помоч в подобном премере?
Люди, есть кнопка (передатчик) и реле (приёмник), реле должно помнить состояние себя, причём оно может его забыть, например перезагрузившись по watchdog. Если кнопка забудет - плевать, её просто нажмут второй раз.
В общем, пришла идея писать это состояние в память, а т. к. включается/выключается регулярно, то писать каждый раз в новое место (следующее за прошлым местом или в начало если прошлым был конец). Покритикуйте функцию.
Которая говорит, куда писала:
#define ESIZE (1024) int AppendEEPROM(byte d){ int i; // счётчик byte b; // буфер boolean f; // флаг f=false; // не писали for(i=0;i<ESIZE;i++){ b=EEPROM.read(i); // ищем инфу if(b!=0xFF){ EEPROM.write(i,0xFF); // возвращаем FF на место if(i<=ESIZE-2){ EEPROM.write(i+1,d); // пишем в следующий байт return i+1; }else{ EEPROM.write(0x0,d); // или если находимся в конце, пишем в ноль return 0; } f=true; // писали // break; // вроде не нужно т. к. return же } } if(!f){ // если не нашли инфы значит память пустая EEPROM.write(0x0,d); // пишем в ноль return 0; } }Которая пишет молча:
#define ESIZE (1024) void AppendEEPROM(byte d){ int i; byte b; boolean f; f=false; for(i=0;i<ESIZE;i++){ b=EEPROM.read(i); if(b!=0xFF){ EEPROM.write(i,0xFF); if(i<=ESIZE-2) EEPROM.write(i+1,d); else EEPROM.write(0x0,d); f=true; break; // а здесь нужно. кстати куда оно выйдет из цикла? } } if(!f) EEPROM.write(0x0,d); // надеюсь что сюда }Поляризованное реле не "забывает" своего состояния, а , наоборот, помнит.....
https://www.google.ru/search?q=%D0%BF%D0%BE%D0%BB%D1%8F%D1%80%D0%B8%D0%B...
Лень доставку ждать :)
А про память есть мнение?
Чё то бардак какой то... Если записываем в ячеку состояние, то нужно сначала прочитать из какой то ячейки номер ячейки в которой записано последнее состояние перед отключением (или перезагрузкоой).
А ты читаешь из ячейки, только что объявленной переменной "i".
цЫкл же?
В том и смысл: мы не знаем куда писать. Ищем то место, которое отличается от 0xFF. "Стираем", записав поверх старой информации 0xFF и в следующий байт пишем. Не?
Читающая функция будет наподобие. Ну и ессно потом допишу "перед тем как писать, прочитать - если то же самое - ничё не делать".
Тут-то суть именно в том чтобы избавиться от "куда писали", потому что - ну пишем мы в первые байты, и в самые последние два - собсно адрес. Значит, эти последние два байта будут изнашиваться в (1024-2)/2=511 раз быстрее. Не? Мы же пишем переменно один/много байт информации в много байт памяти. И два байта адреса в два байта памяти. Надеюсь понятно...
Все правильно. Я бы еще избавился от постоянного поиска нужной ячейки и делал бы его только при старте МК.
#define ESIZE (1024) int curr_addr; // глобально // в сетапе: void InitState() { curr_addr = -1; while(curr_addr < ESIZE) { byte temp = EEPROM.read(++curr_addr); if(temp != 0xFF) { state = temp; // востанавливаем состояние break; } } } void SaveState(byte state) { EEPROM.write(curr_addr++, 0xFF); curr_addr %= ESIZE; EEPROM.write(curr_addr, state); }По поводу записи/чтения EEPROM. Есть такая библиотека, которая умеет сохранять/читать числа с любой размерностью byte int long или даже массивы, причем делает это автоматически. Я пользовался - классная штука. Кому нужно могу на github-е выложить
Ну или вот разбор "по крутому", без ардуино функций
Подскажите как число 999 999 999 (9-ти значное) записывать в память? т.е. метод разделить на старший и младший байт из этой темы не подойдет?
т.е. разделить число на 4 байта
Пойдет, только делите на большее чисто байт. Например так для 3-x байт:
byte b1=value>>16;
byte b2=value>>8;
byte b3=value;
По аналогии хоть 128 битное число раскладывайте, разница будет только в количестве байт.
Ясна спасибо.
Пробую запустить код на запись \ чтение памяти ds1302. Использую доработанную библиотеку отсюда: ссылка
По аналогии из этой темы написал:
long EEPROM_read(int addr){ return word(rtc.readRAM(addr),rtc.readRAM(addr+1),rtc.readRAM(addr+2)); } void EEPROM_Write(int p_address, unsigned long p_value) { byte b1 = ((p_value >> 0) & 0xFF); byte b2 = ((p_value >> 8) & 0xFF); byte b3 = ((p_value >> 8) & 0xFF); rtc.writeRAM(p_address, b1); rtc.writeRAM(p_address + 1, b2); rtc.writeRAM(p_address + 2, b3); } long kontakt = 500000; EEPROM_Write(0, kontakt); kontakt_s = EEPROM_read(0);При компиляции пишет ошибку на строку 2: error: no matching function for call to 'makeWord(uint8_t, uint8_t, uint8_t)'
Подскажите как переписать функцию сбора значения из памяти...
А строка 9 точно верно?
может надо
да верно, опечатался...
Строка word(rtc.readRAM(addr),rtc.readRAM(addr+1)); = Компилируется
Строка word(rtc.readRAM(addr),rtc.readRAM(addr+1),rtc.readRAM(addr+2)); = не компилируется.
Если переделать для памяти конроллера, то так же ошибка. word(EEPROM.read(addr),EEPROM.read(addr+1),EEPROM.read(addr+2));
Не силен в этом. Подскажите как можно собрать значение?
Способ был указан выше
return((rtc.readRAM(addr) << 0) & 0xFF) + ((rtc.readRAM(addr+1) << 8) & 0xFF00)+ ((rtc.readRAM(addr+2) << 16) & 0xFF0000);Спасибо всем. Все работает ;)
А я сделал так. Просто взял придумал 256 иричную систему исчислений :)
Считываю так:
Записываю так:
Короче много способов я думаю можно придумать чтобы разложить число по байтно.
изобретатели велосипедов, посмотрете библиотеку eepromex
Не мучайтесь, вот готовая библиотека
https://github.com/ssvs111/ARDUINO_EEPROM2
Tails_MP, напишите в подфоруме "ищу исполнителя"
Народ доброго дня суток, прошу помощи кто поможет разобраться с EEprom библиотекой. мне нужно после нажатия определенного пункта меню записоватькод Ibuton ключа в eeprom, а потом выводить эти ключи на lcd 1602, определенный ключ в определенном месте..
заранее всем спасибо за помощь)))