Arduino eeprom энергонезависимая память

Запись целых чисел

Запись целых чисел в энергонезависимую память EEPROM осуществить достаточно просто. Внесение чисел происходит с запуском функции EEPROM.write(). В скобках указываются необходимые данные. При этом числа от 0 до 255 и числа свыше 255 записываются по-разному. Первые вносятся просто – их объем занимает 1 байт, то есть одну ячейку. Для записи вторых необходимо использовать операторов highByte() высший байт и lowByte() низший байт.

Число делится на байты и записывается отдельно по ячейкам. Например, число 789 запишется в две ячейки: в первую пойдет множитель 3, а во вторую – недостающее значение. В итоге получается необходимое значение:

3 * 256 + 21 = 789

Для воссоединения» большого целого числа применяется функция word(): int val = word(hi, low). Нужно читывать, что максимальное целое число для записи – 65536 (то есть 2 в степени 16). В ячейках, в которых еще не было иных записей, на мониторе будут стоять цифры 255 в каждой.

Запись чисел с плавающей запятой и строк

Числа с плавающей запятой и строк – это форма записи действительных чисел, где они представляются из мантиссы и показателя степени. Запись таких чисел в энергонезависимую память EEPROM производится с активацией функции EEPROM.put(), считывание, соответственно, – EEPROM.get().

При программировании числовые значения с плавающей запятой обозначаются, как float, стоит отметить, что это не команда, а именно число. Тип Char (символьный тип) – используется для обозначения строк. Процесс записи  чисел на мониторе запускается при помощи setup(), считывание – с помощью loop().

В процессе на экране монитора могут появиться значения ovf, что значит «переполнено», и nan, что значит «отсутствует числовое значение». Это говорит о том, что записанная в ячейку информация не может быть воспроизведена, как число с плавающей точкой. Такой ситуации не возникнет, если достоверно знать, в какой ячейке какой тип информации записан.

Режимы отказа

Существует два вида ограничения хранимой информации: количество перезаписи и длительность хранения.
Во время перезаписи, подзатворный окисленный слой плавучего затвора транзисторов постепенно накапливает в себе электроны. Электрическое поле неподвижных электронов добавляется к полю электронов в плавающем затворе, опуская окно между пороговыми напряжениями. После достаточного количества циклов перезаписи, разница будет слишком мала, чтобы быть узнаваемой, дальнейшая запись информации на устройство невозможно и происходит отказ . Производители обычно указывают максимальное количество перезаписей в 1 млн. или более.

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

Arduino as ISP. Прошивка загрузчика в Ардуино.

Плата Ардуино MOSI MISO SCK Уровень
Uno, Duemilanove 11 или ICSP-4 12 или ICSP-1 13 или ICSP-3
Nano 11 или ICSP-4 12 или ICSP-1 13 или ICSP-3
Pro Mini 11 12 13 3.3В или 5В
Mega1280, Mega2560 51 или ICSP-4 50 или ICSP-1 52 или ICSP-3
Leonardo ICSP-4 ICSP-1 ICSP-3 
Due ICSP-4 ICSP-1 ICSP-3  3.3В
Zero ICSP-4 ICSP-1 ICSP-3 3.3В
101 11 или ICSP-4 12 или ICSP-1 13 или ICSP-3 3.3В
Подключение Uno в качестве программатора к плате Nano через ICSP
  1. В меню Инструменты > Плата выбираем вариант, соответствующий нашей целевой плате.
  2. В меню Инструменты > Программатор выбираем Arduino as ISP.

Инструменты > Записать загрузчикследующей публикации

  • Запускаем Arduino IDE, открываем из примеров скетч ArduinoISP и загружаем его в плату Ардуино, которую будем использовать как программатор.
  • Подключаем к Ардуино-программатору целевую плату по приведенной схеме.
  • Меняем плату в Arduino IDE на целевую.
  • Выбираем в IDE программатор Arduino as ISP.
  • Записываем загрузчик в целевую плату командой из меню IDE.

Arduino EEPROM энергонезависимая память

Энергонезависимая память EEPROM Arduino (Electrically Erasable Programmable Read-Only Memory) — это постоянное запоминающее устройство, которое может хранить записанные в нее данные десятки лет после отключения питания. Количество циклов перезаписи EEPROM памяти несколько сотен тысяч раз при температуре не ниже 24°С, а чтение данных не ограничено. Объем EEPROM памяти Arduino следующий:

  • ATmega168 (плата Arduino Nano) — 512 байт;
  • ATmega328 (плата Arduino Uno, Arduino Nano) — 1 Кбайт;
  • ATmega1280, ATmega2560 (плата Arduino Mega) — 4 Кбайт.

На операцию записи одного байта в EEPROM уходит около 3,3 мкс, а на чтение одного байта уходит около 0,4 мкс (микросекунд). Каждый байт (ячейка) EEPROM в Ардуино по умолчанию (т.е. ни разу не записанная ячейка) имеет значение 255

Обратите внимание, что если данные занимают место больше 1 байта (например, число больше 255), то они разбиваются на несколько ячеек

Это важно учитывать при записи в EEPROM

Introduction to the Serial Peripheral Interface

Serial Peripheral Interface (SPI) is a synchronous serial data protocol used by Microcontrollers for communicating with one or more peripheral devices quickly over short distances. It can also be used for communication between two microcontrollers.

With an SPI connection there is always one master device (usually a microcontroller) which controls the peripheral devices. Typically there are three lines common to all the devices,

  • Master In Slave Out (MISO) — The Slave line for sending data to the master,
  • Master Out Slave In (MOSI) — The Master line for sending data to the peripherals,
  • Serial Clock (SCK) — The clock pulses which synchronize data transmission generated by the master, and
  • Slave Select pin — allocated on each device which the master can use to enable and disable specific devices and avoid false transmissions due to line noise.

The difficult part about SPI is that the standard is loose and each device implements it a little differently. This means you have to pay special attention to the datasheet when writing your interface code. Generally speaking there are three modes of transmission numbered 0 — 3. These modes control whether data is shifted in and out on the rising or falling edge of the data clock signal, and whether the clock is idle when high or low.

All SPI settings are determined by the Arduino SPI Control Register (SPCR). A register is just a byte of microcontroller memory that can be read from or written to. Registers generally serve three purposes, control, data and status.

Control registers code control settings for various microcontroller functionalities. Usually each bit in a control register effects a particular setting, such as speed or polarity.

Data registers simply hold bytes. For example, the SPI data register (SPDR) holds the byte which is about to be shifted out the MOSI line, and the data which has just been shifted in the MISO line.

Status registers change their state based on various microcontroller conditions. For example, the seventh bit of the SPI status register (SPSR) gets set to 1 when a value is shifted in or out of the SPI.

The SPI control register (SPCR) has 8 bits, each of which control a particular SPI setting.

SPCR| 7    | 6    | 5    | 4    | 3    | 2    | 1    |    || SPIE | SPE  | DORD | MSTR | CPOL | CPHA | SPR1 | SPR0 |
SPIE — Enables the SPI interrupt when 1
SPE — Enables the SPI when 1
DORD — Sends data least Significant Bit First when 1, most Significant Bit first when
MSTR — Sets the Arduino in master mode when 1, slave mode when
CPOL — Sets the data clock to be idle when high if set to 1, idle when low if set to
CPHA — Samples data on the falling edge of the data clock when 1, rising edge when
SPR1 and SPR0 — Sets the SPI speed, 00 is fastest (4MHz) 11 is slowest (250KHz)

This means that to write code for a new SPI device you need to note several things and set the SPCR accordingly:

  • Is data shifted in MSB or LSB first?
  • Is the data clock idle when high or low?
  • Are samples on the rising or falling edge of clock pulses?
  • What speed is the SPI running at?

Once you have your SPI Control Register set correctly you just need to figure out how long you need to pause between instructions and you are ready to go. Now that you have a feel for how SPI works, let’s take a look at the details of the EEPROM chip.

Интерфейс

Устройства EEPROM используют последовательный или параллельный интерфейс для ввода/вывода информации.

Устройства с последовательным интерфейсом

Общий интерфейс может быть в виде шин: SPI и I²C, Microwire, UNI/O и 1-Wire.

Типичный EEPROM протокол содержит 3 фазы: Код операции, фазы адреса и фазы данных. Код операции — обычно первые 8 бит, далее следует фаза адреса в 8-24 бита (зависит от устройства) и в конце запись или чтение информации.

Каждое устройство EEPROM, как правило, имеет свой код операций для выполнения различных функций.
Функции для SPI EEPROM могут быть:

  • Write Enable (WRENAL)
  • Write Disable (WRDI)
  • Read Status Register (RDSR)
  • Write Status Register (WRSR)
  • Read Data (READ)
  • Write Data (WRITE)


EEPROM на печатной плате карты памяти ПК.

Ряд других операций, которые поддерживают некоторые EEPROM устройства:

  • Program
  • Sector Erase
  • Chip Erase commands

Устройства с параллельным интерфейсом

Параллельные устройства EEPROM обычно содержат в себе 8-битную шину данных и адресную шину достаточного объёма для покрытия всей памяти. Большинство таких устройств имеют защиту записи на шинах и возможность выбора чипа. Некоторые микроконтроллеры содержат в себе такие интегрированные EEPROM.
Операции на таких устройствах проще и быстрее в сравнении с последовательным интерфейсом EEPROM, но за счет того, что для его функционирования требуется большое количество точек вывода (28pin и больше), параллельная память EEPROM теряет популярность уступая место памяти типа Flash и последовательной EEPROM.

Другие устройства

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

EEPROM Get

The purpose of this example is to show how the put and get methods provide a different behaviour than write and read, that work on single bytes. Getting different variables from EEPROM retrieve a number of bytes that is related to the variable datatype.

Code

/***
    eeprom_get example.
    This shows how to use the EEPROM.get() method.
    To pre-set the EEPROM data, run the example sketch eeprom_put.
    This sketch will run without it, however, the values shown
    will be shown from what ever is already on the EEPROM.
    This may cause the serial object to print out a large string
    of garbage if there is no null character inside one of the strings
    loaded.
    Written by Christopher Andrews 2015
    Released under MIT licence.
***/#include <EEPROM.h>void setup() {
  float f = 0.00f;   //Variable to store data read from EEPROM.
  int eeAddress = ; //EEPROM address to start reading from
  Serial.begin(9600);
  while (!Serial) {
    ; // wait for serial port to connect. Needed for native USB port only
  }
  Serial.print(«Read float from EEPROM: «);
  //Get the float data from the EEPROM at position ‘eeAddress’
  EEPROM.get(eeAddress, f);
  Serial.println(f, 3);    //This may print ‘ovf, nan’ if the data inside the EEPROM is not a valid float.
  /***
    As get also returns a reference to ‘f’, you can use it inline.
    E.g: Serial.print( EEPROM.get( eeAddress, f ) );
  ***/
  /***
    Get can be used with custom structures too.
    I have separated this into an extra function.
  ***/
  secondTest(); //Run the next test.}
struct MyObject {
  float field1;
  byte field2;
  char name10;};void secondTest() {
  int eeAddress = sizeof(float); //Move address to the next byte after float ‘f’.
  MyObject customVar; //Variable to store custom object read from EEPROM.
  EEPROM.get(eeAddress, customVar);
  Serial.println(«Read custom object from EEPROM: «);
  Serial.println(customVar.field1);
  Serial.println(customVar.field2);
  Serial.println(customVar.name);}void loop() {
  /* Empty loop */}

See also

  • EEPROM.get()
  • EEPROM library reference
  • EEPROM Clear — Fills the content of the EEPROM memory with “0”.
  • EEPROM Read – Reads values stored into EEPROM and prints them on Serial.
  • EEPROM Write – Stores values read from A0 into EEPROM.
  • EEPROM Crc – Calculates the CRC of EEPROM contents as if it was an array.
  • EEPROM Iteration – Programming examples on how to go through the EEPROM memory locations.
  • EEPROM Put – Put values in EEPROM using variable semantics (differs from EEPROM.write() ).
  • EEPROM Update – Stores values read from A0 into EEPROM, writing the value only if different, to increase EEPROM life.

Last revision 2018/05/17 by SM

Скетч записи и чтения данных из EEPROM

Для работы EEPROM в arduino IDE уже есть встроенная библиотека EEPROM.h, ее и будем использовать. Вся память разбита на ячейки по 1 байту, соответственно в каждую ячейку можно записать не больше одного байта, если хранить целые числа, то можно записывать значения от 0 до 255 без сложностей

Этим мы и займемся в скетче – используем одну ячейку памяти и сначала сохраним в нее число от 0 до 4, а потом прочитаем содержимое.
Если вам необходимо хранить значения, превышающие размер в 1 байт, то их придется разбивать по байтам и записывать в разные ячейки по частям.Обратите внимание: по умолчанию в пустой EEPROM в каждой ячейке хранятся значения 255. Но делать проверку на пустоту с помощью сравнения с числом 255 не стоит

Поскольку не всегда можно полагаться на заводские настройки. И перед использованием лучше прогнать все ячейки в цикле и записать в них свои значения для обнуления, чтобы быть полностью уверенным в содержимом.
Далее остается только привести скетч с подробными комментариями:

#include <EEPROM.h> // библиотека для работы с EEPROM

int pin_rezistor = A0;
int value = 0;
int count_leds = 0;

// пин светодиода
int ledPins = {4, 5, 6, 7,8}; 
boolean editOn = false; // состояние светодиода

// пин кнопки
int btn_1 = 2; 
boolean lastBtn_1 = false; // предыдущее состояние кнопки
boolean currentBtn_1 = false; // текущее состояние кнопки

void setup() {  
  // режимы работы пинов
  pinMode(pin_rezistor, INPUT);
  pinMode (btn_1, INPUT);
  for(int i=0; i<=4; i++){
    pinMode (ledPins, OUTPUT);  
  }   
}

void loop() {
  if(editOn){
    value = analogRead(pin_rezistor); 
    count_leds = map(value, 0, 1000, 0, 4);
  }else{
    count_leds = EEPROM_int_read(0);
  }
  
  // получение состояния кнопки
  currentBtn_1 = isBtnStatus(lastBtn_1);
  // если кнопка была нажата 5 миллисекунд и более
  if (lastBtn_1 == false && currentBtn_1 == true) { 
    // меняем состояние светодиода
    editOn = !editOn; 
    // если выключился режим настройки
    if(!editOn){
      EEPROM.write(0, count_leds);
    }
  }
  // сохраняем состояние кнопки
  lastBtn_1 = currentBtn_1;

  // все гасим
  for(int i=0; i<=4; i++){
    digitalWrite(ledPins, LOW);  
  } 
  // включаем нужное количество
  for(int i=0; i<=count_leds; i++){
    digitalWrite(ledPins, HIGH);  
  }
  delay(50);
}

// функция для определения состояния кнопки
boolean isBtnStatus(boolean last) { 
  // считываем состояние кнопки
  boolean current = digitalRead(btn_1);
  // сравниваем текущее состояние кнопки со старым
  if (last != current) { 
    // ждем 5 миллисекунд
    delay(5);
    // считываем состояние кнопки еще раз
    current = digitalRead(btn_1);
  }
  // возвращаем состояние кнопки
  return current; 
}


// чтение
int EEPROM_int_read(int addr) {    
  byte raw;
  for(byte i = 0; i < 2; i++) raw = EEPROM.read(addr+i);
  int &num = (int&)raw;
  return num;
}

// запись
void EEPROM_int_write(int addr, int num) {
  byte raw;
  (int&)raw = num;
  for(byte i = 0; i < 2; i++) EEPROM.write(addr+i, raw);
}
 

Список производителей EEPROM

Список производителей EPROM смотрите на сайте Yahoo и сходите в
economy->company->Hardware->Peripherals->Device programmers.

Yahoo URL для EPROMs таков http://dir.yahoo.com/Business_and_Economy/Companies/Computers/Hardware/Peripherals/Device_Programmers/

  • Advanced Research Technology B.V — разработка, производство и продажа оборудования программирования; разработка аппаратуры и программ.

  • Elnec, Presov — производители программаторов, эмуляторов и симуляторов.

  • Advin Systems Inc. — устройства программирования для ПК,
    которые поддерживают последние типы корпусов и технологии.

  • Andromeda Research Labs — производитель портативных программаторов и систем программирования.

  • B and C Microsystems, Inc — предлагает тесты и оборудования для дублирования/программирования PCMCIA (PC) Card, ISA/PCI карт, SIMM, устройств памяти (включая FLASH), PLD.

  • BP Microsystems — устройства программирования.

  • Bytek — разработка, дизайн, производство
    и продажа микропроцессорных, модульных электронных систем используемых для программирования полупроводниковых устройств. Список производимой продукции включает ChipBurner.

  • Concentrated Programming Ltd — предлагает полный диапазон решений для программирования устройств.

  • Dataman Programmmers Ltd. — производство наладонных EPROM программатора/эмулятора. Также продает программаторы для ПК, и Gang-Pro программаторы.

  • General Device Instruments — программаторы IC устройств. Универсальный и Gang программаторы для Pld, Flash, микроконтроллеров, Prom, EEprom, Памяти, Epld, Mach и многих других ic устройств.

  • HI-LO System Research Co., Ltd. — производство универсальных и gang программаторов.

  • ICE Technology — EPROM и универсальные программаторы с поддержкой памяти, микроконтроллеров, и программируемых логических устройств.

  • Iceprom — стираемая программируемая ROM.

  • International Microsystems Inc — Высокоскоростной gang программатор. (PROM, FLASH, Микроконтроллер, карты памяти PCMCIA).

  • JED Microprocessors Pty. Ltd. — вставляется в порт принтера ПК, и способен программировать 28-контактные или 32-контактные микросхемы EPROM и FLASH.

  • Logical Devices, Inc — программирование устройств PLD, FPGA, PROM, микроконтроллеров. Производит CUPL компилятор для программируемой логики и программаторы ALLPRO и Chipmaster.

  • MCL Systems — новый метод не только программирования, но и разработки новой аппаратуры с помощью Integrated Controller Unit. И вам не нужно быть профессионалом.

  • MQP Electronics — производитель универсальных программаторов, gang программаторов, программ, и пакетов преобразования. Высокая пропускная способность и надежность.

  • Needham’s Electronics — производитель программаторов.

  • NP Programming Services — реализует программирование памяти и компонентов логики.

  • Program Automation, Inc. — независимая кампания, специализирующаяся на программировании высокоемких PROM, включая flash I/C.

  • Stag Programmers Inc — производитель программаторов prom и логики, производство оборудования и ультрафиолетовых устройств стирания.

  • Sunrise Electronics — универсальные программаторы, gang и in-circuit программаторы с пожизненной поддержкой.

  • System General Co. — программаторы, устройства записи EPROM и IC тестеры

  • Tribal Microsystems — универсальный и gang программаторы, 8051 и EPROM эмуляторы, тестовые сокеты, сокеты для создания и сокеты для производства.

Принцип действия

Принцип работы EEPROM основан на изменении и регистрации электрического заряда в изолированной области (кармане) полупроводниковой структуры.

Ячейка памяти EEPROM представляет собой транзистор, в котором затвор выполняется из поликристаллического кремния. Затем этот затвор окисляется и в результате он будет окружен оксидом кремния — диэлектриком с прекрасными изолирующими свойствами. Изменение заряда («запись» и «стирание») производится приложением между затвором и истоком большого потенциала, чтобы напряженность электрического поля в тонком диэлектрике между каналом транзистора и карманом оказалась достаточна для возникновения туннельного эффекта. Для усиления эффекта туннелирования электронов в карман при записи применяется небольшое ускорение электронов путём пропускания тока через канал полевого транзистора (явление инжекции горячих носителей). После снятия программирующего напряжения индуцированный заряд остаётся на плавающем затворе, и, следовательно, транзистор остаётся в проводящем состоянии. Заряд на его плавающем затворе может храниться десятки лет.
Чтение выполняется полевым транзистором, для которого карман выполняет функцию затвора. Потенциал плавающего затвора изменяет пороговые характеристики транзистора, что и регистрируется цепями чтения.

Ранее подобная конструкция ячеек применялась в ПЗУ с ультрафиолетовым стиранием (EPROM).Сейчас особенностью классической ячейки EEPROM можно назвать наличие второго транзистора, который помогает управлять режимами записи и стирания. Стирание информации производится подачей на программирующий затвор напряжения, противоположного напряжению записи. В отличие от ПЗУ с ультрафиолетовым стиранием, время стирания информации в EEPROM памяти составляет около 10 мс. Структурная схема энергонезависимой памяти с электрическим стиранием не отличается от структурной схемы масочного ПЗУ. Единственное отличие — вместо плавкой перемычки используется описанная выше ячейка.

Некоторые реализации EEPROM выполнялись в виде одного трёхзатворного полевого транзистора (один затвор плавающий и два обычных). Эта конструкция снабжается элементами, которые позволяют ей работать в большом массиве таких же ячеек. Соединение выполняется в виде двумерной матрицы, в которой на пересечении столбцов и строк находится одна ячейка. Поскольку ячейка EEPROM имеет третий затвор, то, помимо подложки, к каждой ячейке подходят 3 проводника (один проводник столбцов и 2 проводника строк).


Упрощенная структурная схема EEPROM.

Arduino EEPROM примеры использования

Для начала рассмотрим запись в EEPROM Arduino числа больше, чем 255, например число 999. При записи в EEPROM число 999 будет разбиваться на множитель (старший байт) и недостающее число (младший байт), занимая при этом уже две ячейки в энергонезависимой памяти (т.е. 999 = 3×256 + 231). Чтобы вывести сохраненное число на монитор порта, его нужно будет «собрать» с помощью функции .

Скетч. Запись в память EEPROM int, float

#include <EEPROM.h>  // импортируем библиотеку

int num = 999;                      // разбиваем число на 2 байта
byte hi  = highByte(num);   // старший байт
byte low = lowByte(num);  // младший байт

void setup() {
  Serial.begin(9600);    // запускаем монитор порта

   EEPROM.update(1, hi);     // записываем старший байт в ячейку 1
   EEPROM.update(2, low); // записываем младший байт в ячейку 2

  delay(1000);

  byte val1 = EEPROM.read(1);  // считываем 1 байт по адресу ячейки
  byte val2 = EEPROM.read(2);  // считываем 1 байт по адресу ячейки

  Serial.println("highByte - "+String(val1));  // выводим старший байт на монитор
  Serial.println("lowByte  - "+String(val2));  // выводим младший байт на монитор

  int NUM = word(hi, low);       // "собираем" число из байтов
  Serial.println("int num  - "+String(NUM));    // выводим полученное число
}

void loop() {
}

Пояснения к коду:

  1. для записи данных в ячейку в программе использована функция , которая перезаписывает ячейку только в случае различия сохраняемых данных с данными в ячейке EEPROM Arduino Uno;
  2. основная проблема с сохранением больших чисел (int, float) в память EEPROM заключается в том, чтобы случайно не перезаписать нужную ячейку новой информацией. Для этого нужно учитывать размер сохраняемых данных в ПЗУ, используя функции и .

Скетч. Запись строк в EEPROM (String)

#include <EEPROM.h>  // импортируем библиотеку

int address = 10;  // адрес первой ячейки для записи

long cod = 8904; // разбиваем телефонный номер на две части
long tel = 2768282;
String email = "ROBOTEHNIKA18@GMAIL.COM"; // сохраняем в строке адрес почты

long COD; // создаём новые переменные для чистоты эксперимента
long TEL;
String EMAIL;

void setup() {
  Serial.begin(9600);  // запускаем монитор порта

  EEPROM.put(address, cod);      // сохраняем код телефона в памяти Ардуино
  address += sizeof(cod);              // узнаем адрес следующей свободной ячейки
  EEPROM.put(address, tel);       // сохраняем номер телефона в памяти Ардуино
  address += sizeof(tel);                // узнаем адрес следующей свободной ячейки
  EEPROM.put(address, email);  // сохраняем электронную почту в памяти

  address = 10;  // адрес первой ячейки для чтения

  Serial.print("Phone: ");  // выводим телефонный номер на монитор
  Serial.print(EEPROM.get(address, COD));
  address += sizeof(COD);
  Serial.println(EEPROM.get(address, TEL));
  address += sizeof(TEL);

  Serial.print("Email: ");  // выводим электронную почту на монитор
  Serial.println(EEPROM.get(address, EMAIL));
}

void loop() {
}

Пояснения к коду:

  1. перед сохранением новых данных в памяти, следует узнать размер данных, которые были сохранены, чтобы начать запись в новой ячейке;
  2. удалив из кода строчки для записи данных, вы можете каждый раз при запуске программы считывать все сохраненные данные из ПЗУ Ардуино.

Предотвращение повреждения EEPROM

Если напряжение питания VCC слишком низкое (например, во время включения питания), данные в EEPROM можно повредить, потому что нарастание напряжения может оказаться слишком медленным для процессора и EEPROM, что не позволит им работать правильно. Эти вопросы такие же, как для систем, использующих память EEPROM, и должны быть применены такие же проектные решения.

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

Повреждения данных EEPROM можно легко избежать, следуя этому совету по проектированию:

Поддерживайте активный (низкий) сброс AVR во время недостаточного напряжения питания. Это можно сделать, включив внутренний детектор (Brown-out Detector (BOD)). Если уровень напряжения BOD не соответствует необходимому уровню напряжения, то можно использовать внешнюю цепь сброса, поддерживающую низкий уровень на выводе сброса и предохраняющую EEPROM от порчи. Если сброс происходит во время выполнения операции записи, операция записи будет завершена при условии, что напряжение питания достаточно.

ПРИМЕЧАНИЕ
Обычно все типовые схемы предусматривают такую защиту без дополнительного программирования (без использования BOD). Самое простое решение — подключить вход сброса микроконтроллера к плюсу источника питания через резистор, а к минусу — через конденсатор. При подаче питания на входе сброса будет низкий уровень, пока не зарядится конденсатор. То есть микроконтроллер не запустится, пока не зарядится конденсатор. Остаётся только рассчитать номиналы резистора и конденсатора, но это уже другая тема…

Описание памяти EEPROM

Arduino – это целое семейство различных устройств для создания электронных проектов. Микроконтроллеры очень удобны для использования, доступны к освоению даже новичку. Каждый микроконтроллер состоит из платы, программ для обеспечения работы, памяти. В этой статье будет рассмотрена энергонезависимая память, используемая в Arduino.

Ардуино предоставляет своим пользователям три типа встроенной памяти устройств: стационарное ОЗУ (оперативно-запоминающее устройство или SRAM — static random access memory) – необходимо для записи и хранения данных в процессе использования; флеш-карты – для сохранения уже записанных схем; EEPROM – для хранения и последующего использования данных.

По теме: Скачать библиотеку EEPROM

На ОЗУ все данные стираются, как только происходит перезагрузка устройства либо отключается питание. Вторые две сохраняют всю информацию до перезаписи и позволяют извлекать ее при необходимости. Флеш-накопители достаточно распространены в настоящее время. Подробнее стоит рассмотреть память EEPROM.

Аббревиатура расшифровывается, как Electrically Erasable Programmable Read-Only Memory и в переводе на русский дословно означает – электрически стираемая программируемая память только для чтения. Производитель гарантирует сохранность информации на несколько десятилетий вперед после последнего отключения питания (обычно приводят срок в 20 лет, зависит от скорости снижения заряда устройства).

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

Объем памяти, в сравнении с современными носителями, очень небольшой и разный для различных микроконтроллеров. Например, для:

  • ATmega328 – 1кБ
  • ATmega168 и ATmega8 – 512 байт,
  • ATmega2560 и ATmega1280 – 4 кБ.

Так устроено потому, что каждый микроконтроллер предназначен для определенного объема задач, имеет разное количество выводов для подключения, соответственно, необходим разный объем памяти. При этом такого количества достаточно для обычно создаваемых проектов.

Для записи на EEPROM требуется значительное количество времени – около 3 мс. Если в момент записи отключается питание, данные не сохраняются вовсе либо могут быть записаны ошибочно. Требуется всегда дополнительно проверять внесенную информацию, чтобы избежать сбоев во время работы. Считывание данных происходит гораздо быстрее, ресурс памяти от этого не снижается.

Запись EEPROM

Для записи ячейки памяти пользователь должен записать адрес в EEARL, а данные — в EEDR. Если биты EEPMn равны 0b10, то запись EEPE (в течение четырех тактов после записи EEMPE) вызовет только операцию записи (время программирования приведено выше в таблице 5-1). В EEPE бит остается установленным до тех пор, пока операция записи не завершится. Если записываемая ячейка не была очищена (стерта) перед записью, сохраненные данные должны считаться потерянными. Пока микроконтроллер занят программированием, невозможно выполнить какие-либо другие операции с EEPROM.

Калибровка генератора тактовой частоты с помощью регистра калибровки (Oscillator Calibration Register) используется для настройки времени доступа к EEPROM. Убедитесь, что частота генератора соответствует требованиям, описанным в разделе “OSCCAL – Oscillator Calibration Register » (в оригинальной документации стр. 27, на моём сайте будет описана позже).

В следующих примерах кода показана одна функция на Ассемблере и C для стирания, записи или атомарной записи EEPROM. В примерах предполагается, что прерывания управляются (например, отключением прерываний глобально) таким образом, что во время выполнения этих функций прерывания не будут происходить.

EEPROM_write:
; Дождаться завершения предыдущей записи
sbic EECR, EEPE
rjmp EEPROM_write
; Установить режим программирования
ldi r16, (0<<EEPM1)|(0<<EEPM0)
out EECR, r16
; Записать начальный адрес (r17) в регистр адреса
out EEARL, r17
; Записать данные (r16) в регистр данных
out EEDR, r16
; Записать логическую единицу в EEMPE
sbi EECR, EEMPE
; Начать запись EEPROM, установив EEPE
sbi EECR, EEPE
ret
void EEPROM_write(unsigned char ucAddress, unsigned char ucData)
{
/* Дождаться завершения предыдущей записи */
while(EECR & (1<<EEPE)) ;
/* Установить режим программирования */
EECR = (0<<EEPM1)|(0>>EEPM0)
/* Настроить регистры адреса и данных */
EEARL = ucAddress;
EEDR = ucData;
/* Записать логическую единицу в EEMPE */
EECR |= (1<<EEMPE);
/* Начать запись EEPROM, установив EEPE */
EECR |= (1<<EEPE);
}

См. также пример здесь.

В следующих примерах кода показаны функции на Ассемблере и C для чтения EEPROM. В примерах предполагается, что прерывания управляются таким образом, чтобы во время выполнения этих функций не возникало прерываний.

EEPROM_read:
; Дождаться завершения предыдущей записи
sbic EECR, EEPE
rjmp EEPROM_read
; Записать начальный адрес (r17) в регистр адреса
out EEARL, r17
; Начать запись EEPROM, записав EERE
sbi EECR, EERE
; Читать данные из регистра данных
in r16, EEDR
ret
unsigned char EEPROM_read(unsigned char ucAddress)
{
/* Дождаться завершения предыдущей записи */
while(EECR & (1<<EEPE))
;
/* Настроить регистра адреса */
EEARL = ucAddress;
/* Начать чтение EEPROM, записав EERE */
EECR |= (1<<EERE);
/* Вернуть данные из регистра данных */
return EEDR;
}

См. также пример здесь.

Библиотека

Работа с памятью EEPROM осуществляется с помощью библиотеки, которая была специально создана для Ардуино. Главными являются способность к записи и чтению данных. Библиотека активируется командой #include EEPROM.h.

Далее используются простые команды:

  • для записи – EEPROM.write(address, data);
  • для чтения – EEPROM.read(address).

В данных скетчах: address – аргумент с данными ячейки, куда вносятся данные второго аргумента data; при считывании используется один аргумент address, который показывает, откуда следует читать информацию.

Функция Назначение
read(address) считывает 1 байт из EEPROM; address – адрес, откуда считываются данные (ячейка, начиная с 0);
write(address, value) записывает в память значение value (1 байт, число от 0 до 255) по адресу address;
update(address, value) заменяет значение value по адресу address, если её старое содержимое отличается от нового;
get(address, data) считывает данные data указанного типа из памяти по адресу address;
put(address, data) записывает данные data указанного типа в память по адресу address;
EEPROM позволяет использовать идентификатор «EEPROM» как массив, чтобы записывать данные в память и считывать их из памяти.

1Описание последовательного интерфейса SPI

SPI – Serial Peripheral Interface или «Последовательный периферийный интерфейс» – это синхронный протокол передачи данных для сопряжения ведущего устройства (Master) с периферийными устройствами (Slave). Ведущим устройством часто является микроконтроллер. Связь между устройствами осуществляется по четырём проводам, поэтому SPI иногда называют «четырёхпроводной интерфейс». Вот эти шины:

Название Назначение шины SPI
MOSI (Master Out Slave In) линия передачи данных от ведущего к ведомым устройствам;
MISO (Master In Slave Out) линия передачи от ведомого к ведущему устройству;
SCLK (Serial Clock) тактовые импульсы синхронизации, генерируемые ведущим устройством;
SS (Slave Select) линия выбора ведомого устройства; когда на линии логический «0», ведомое устройство «понимает», что сейчас обращаются к нему.

Существует четыре режима передачи данных (SPI_MODE0, SPI_MODE1, SPI_MODE2, SPI_MODE3), обусловленные сочетанием полярности тактовых импульсов (работаем по уровню HIGH или LOW), Clock Polarity, CPOL, и фазой тактовых импульсов (синхронизация по переднему или заднему фронту тактового импульса), Clock Phase, CPHA. В последнем столбце таблицы приведены поясняющие иллюстрации. На них Sample обозначены моменты, когда данные на линии должны быть готовы и считываются устройствами

Буквой Z отмечено, что состояние данных на линии неизвестно или не важно

Режим Полярность тактовых импульсов (CPOL) Фаза тактовых импульсов (CPHA) Диаграмма режима
SPI_MODE0
SPI_MODE1 1
SPI_MODE2 1
SPI_MODE3 1 1

Интерфейс SPI предусматривает несколько вариантов подключения ведомых устройств: независимое и каскадное. При независимом подключении к шине SPI ведущее устройство обращается к каждому ведомому устройству индивидуально. При каскадном подключении ведомые устройства срабатывают поочерёдно, как бы каскадом.

Виды подключения устройств для работы по интерфейсу SPI: независимое и каскадное

Оцените статью:
Оставить комментарий