Библиотека EEPROM

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

Объем памяти EEPROM различных микроконтроллеров, входящих в состав Ардуино, может отличаться: 1024 байта в ATmega328, 512 байт - в ATmega168 и ATmega8, 4 КБ (4096 байт) - в ATmega1280 и ATmega2560.

 

Микроконтроллеры ATmega имеют на борту энергонезависимую память EEPROM, не потеряющую записанные в нее данные даже после отключения питания. 512 байтов такой памяти несут ATmega8 и ATmega168, 1024 байта — ATmega328, 4096 байтов — Arduino Mega. Память типа EEPROM допускает несколько десятков тысяч циклов записи и стирания данных. Она может пригодиться для сохранения изменяющихся настроек при отключении питания от устройств Arduino. Для работы с этой памятью в составе Arduino IDE имеется удобная библиотека EEPROM.

 

Функции библиотек EEPROM

 

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

 

Функция чтения EEPROM.read

 

Функция EEPROM.read считывает байт из энергонезависимой памяти EEPROM. Если байт до этого никогда не перезаписывался — вернет значение 255.

 

Синтаксис функции EEPROM.read: EEPROM.read(address)

Параметр: address — порядковый номер ячейки памяти для чтения от 0 до 512 (или 1024) (int);

Возвращаемое значение — байт, хранимый в ячейке памяти.

 

Пример считывания значения всех байтов энергонезависимой памяти EEPROM и вывода их в COM-порт представлен в примере.

 

#include <EEPROM.h>

// начальный адрес памяти EEPROM int address = 0;

 

byte value; void setup()

{

Serial.begin(9600);

}

void loop()

{

// считываем значение по текущему адресу EEPROM value = EEPROM.read(address);

Serial.print(address); Serial.print("\t"); Serial.print(value, DEC); Serial.println();

// устанавливаем следующую ячейку памяти address = address + 1;

// EEPROM содержит всего 512(1024) байт

// если адрес достиг 512(1024), то снова переходим на 0 if (address == 512)

address = 0; delay(500);

}

 

Функция записи EEPROM.write

 

Функция EEPROM.write записывает байт в энергонезависимую память.

 

Синтаксис функции EEPROM.write:

EEPROM.write(address, value)

Параметры:

 address — порядковый номер ячейки памяти для записи — от 0 до 511 (int);

 value — байт для записи — от 0 до 255 (byte). Возвращаемого значения нет.

 

Возможное количество циклов перезаписи данных (Write/Erase Cycles) в памяти ограничено 100 тыс. раз — это следует учитывать при использовании данной памяти. Время, требуемое для завершения цикла записи, составляет 3,3 ms. Данная задержка уже учитывается библиотекой EEPROM.

Пример сохранения в энергонезависимой памяти EEPROM значений, считанных с аналогового входа analog input 0, представлен в листинге 8.2. Данные значения останутся в памяти и после отключения питания от платы и в будущем могут быть доступны для другого скетча.

 

#include <EEPROM.h>

// текущее значение адреса EEPROM int addr = 0;

void setup()

{;}

void loop()

{

if (addr < 512)

{

// EEPROM может хранить только значения от 0 до 255. int val = map(analogRead(0),0,1024,0,256);

// записываем значение в энергонезависимую память EEPROM.write(addr, val);

// устанавливаем следующую ячейку памяти. addr = addr + 1;

}

}

 

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

 

Воспроизведение звука

Создадим проект, в котором устройство Arduino используется для генерации звука. Мелодии хранятся в памяти EEPROM и выводятся на динамик. Для этого на динамик следует подать сигнал соответствующей частоты. В качестве динамика используем динамическую головку 8 Ом, подключаемую к выводу D8. Схема подключения представлена на рисунке.

 
 Схема включения

 

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

Схема включения с транзистором

Громкость при этом получается весьма большой, поэтому в схему в качестве регулятора громкости добавлен потенциометр R2. Транзистор включен по схеме с общим эмиттером, и в данном случае выступает не в роли усилителя, а в качестве электронного ключа для согласования нагрузок. Дело в том, что у динамической головки сопротивление очень маленькое, и при подаче на нее напряжения +5 В через нее станет протекать ток около 625 мА. Однако максимальный ток, который могут обеспечить все выводы микроконтроллера, составляет всего 150 мА, т. е. в 4 раза меньше. И таким образом, подключая динамик к микроконтроллеру не напрямую, а через транзистор, способный пропускать через себя большее напряжение и ток большей силы, мы обеспечиваем электрическое согласование — в данном случае согласование по току.

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

 

Для подачи частотного сигнала на динамик воспользуемся функцией tone(). Скетч для воспроизведения мелодии представлен в примере сопровождающего книгу электронного архива.

Таблица расчета тонов для нот одной октавы

 

 

// ноты мелодии

char notes[]="GECgabCaCg DGECabCDED EFEDGEDC CECaCag gCEDgCEDEFGECDgC "; // пробел - это пауза

// длительность для каждой ноты и паузы

int beats[] = { 4, 4, 4, 4, 1, 1, 1, 2, 1, 4, 2, 4, 4, 4, 4, 1, 1, 1, 2,

1,4, 2, 1, 1, 1, 1, 2, 1, 1, 4, 2, 1, 2, 1, 2, 1, 1, 4, 2, 1,

2, 1, 2, 1, 2, 1, 2, 1, 1, 1, 1, 1, 2, 1, 4, 4, 4} ;

// подключить динамик к pin 8 int speakerPin = 8;

int length = sizeof(beats); // число нот

// темп воспроизведения int tempo = 400;

// проиграть ноту

void playNote(char note, int duration)

{

// массив для наименований нот (до ре ми ... и т. д. в пределах двух

// октав)

char names[]={'c','d','e','f','g','a','b','C','D','E','F','G','A','B'}; int tones[]={3830,3400,3038,2864,2550,2272,2028,1912,1700,

1518,1432,1276,1136,1014 };

// проиграть тон, соответствующий ноте for (int i = 0; i < sizeof(tones); i++)

{

if (names[i] == note) tone(speakerPin,tones[i],duration * 1000L);

}

}

 

void setup()

{pinMode(speakerPin, OUTPUT);}

void loop()

{

for (int i = 0; i < length; i++)

{

if (notes[i] == ' ')

tone(speakerPin,0, beats[i]*tempo* 1000L); // пауза else

playNote(notes[i], beats[i] * tempo);

}

// пауза между нотами delay(tempo / 2);

}

delay(3000);

}

 

Звонок с мелодиями

 

Проигрывать мелодию через динамик мы уже умеем. Теперь напишем скетч загрузки мелодий в память EEPROM. Зарезервируем там место для 10 мелодий, которые сможем проигрывать в нужный момент. Карта адресов памяти будет иметь следующий вид:

 0-9 — указатель на адрес мелодии;

 10-511 — место для мелодий.

Каждая мелодия будет представлять следующую последовательность данных: tempo(2 байта), нота1, длит.1, нота2, длит.2 ,..., нотаN, длит.N, end где:

 tempo — темп проигрываемой мелодии;

 нота1, нота2 ,..., нотаN — ноты;

 длит1, длит2 ,..., длитN — длительности проигрывания нот;

 end — байт конца мелодии (значение 0).

Запись последовательности нот и длительности их воспроизведения для каждой мелодии хранятся в массивах. В нашем скетче мы после записи мелодий в память EEPROM выведем содержимое памяти EEPROM. Фрагмент содержимого скетча представлен в примере.

 

// Использование библиотеки EEPROM

// запись мелодий в EEPROM

// подключение библиотеки EEPROM

#include <EEPROM.h>

// ноты мелодии

String notes[] ={ "ccggaagffeeddc ",

"GECgabCaCg DGECabCDED EFEDGEDC CECaCag gCEDgCEDEFGECDgC "};

// пробел - это пауза

// длительность для каждой ноты и паузы

String beats[]={"1,1,1,1,1,1,2,1,1,1,1,1,1,2,4", "4,4,4,4,1,1,1,2,1,4,2,4,4,4,4,1,1,1,2,1,4,2,1,1,1,1,2,1,1,4,2,1,

2,1,2,1,1,4,2,1,2,1,2,1,2,1,2,1,1,1,1,1,2,1,4,4,4"} ;

int tempo[]= {300,400};

.........

int addr1=0; int addr2=10;

void write_melody(int num)

{

EEPROM.write(addr1,addr2); // указатель на мелодию EEPROM.write(addr2,tempo[num]>>8); // для tempo – 2 байта addr2++;

EEPROM.write(addr2,tempo[num]); addr2++;

for(int j=0;j<notes[num].length();j++)

{

EEPROM.write(addr2,notes[num][j]); // нота addr2++;

EEPROM.write(addr2,beats[num][j*2]); // длительность addr2++;

Serial.print(notes[num][j]);Serial.print(" "); Serial.print(beats[num][j*2]-48);Serial.println(" ");

}

// записать 0 - end EEPROM.write(addr2,0); addr2++;

addr1++;

}

void setup()

{

.........

for(int i=0;i<sizeof(tempo)/2;i++)

{write_melody(i);}

Serial.println("end..."); Serial.println("control..."); for(int i=0;i<511;i++)

{

Serial.print(i);Serial.print(" - ");

 

Serial.println(EEPROM.read(i),DEC);

}

}

void loop()

{;}

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

А теперь напишем скетч, проигрывающий случайную мелодию из памяти EEPROM при нажатии кнопки. Схема при этом изменяется незначительно. Один контакт кнопки подсоединяем к D9. К нему же подключаем подтягивающий резистор 10 кОм, который в свою очередь соединяем с землей. Другой выход кнопки соединяем с питанием 5 В. При включении в программе setup() подсчитаем количество записанных мелодий. Затем в цикле на динамик выдается мелодия. Данные мелодии (темп, список нот и их продолжительность) берутся из памяти EEPROM. Для контроля данные выводятся в монитор последовательного порта.

 

// ***** Воспроизведение мелодии, записанной в EEPROM

// подключение библиотеки EEPROM

#include <EEPROM.h>

// подключить динамик к pin 8 int speakerPin = 8;

// подключить кнопку к pin 9 int buttonPin = 9;

// темп воспроизведения, ноты, длительности int tempo,notes,beats;

// адрес указателя мелодии, случайная мелодия, количество мелодий int addr1;

int rand1; int count=0;

// проиграть ноту

void playNote(char note, int duration)

{

// массив для наименований нот (до ре ми ... и т. д. в пределах двух октав) char names[] = { 'c', 'd', 'e', 'f', 'g', 'a', 'b',

'C','D','E','F','G','A','B' };

int tones[] = { 3830, 3400, 3038, 2864, 2550, 2272, 2028, 1912, 1700, 1518,

1432, 1276, 1136, 1014 };

// проиграть тон, соответствующий ноте for (int i = 0; i < sizeof(tones); i++)

{

if (names[i] == note)

 

{

tone(speakerPin,tones[i],duration * 1000L);

}

}

}

void setup()

{

pinMode(speakerPin, OUTPUT); pinMode(buttonPin, INPUT); Serial.begin(9600);

for(int i=0;i<200;i++)

{

Serial.print(i);Serial.print(" - "); Serial.println(EEPROM.read(i),DEC);

}

int i=0; while(EEPROM.read(i)<255)

{count++;i++;} Serial.print("count=");Serial.println(count);

}

void loop()

{

if(digitalRead(buttonPin)==HIGH)

{

Serial.println("click");

// получить случайное rand1=random(0,count+1); addr1=EEPROM.read(rand1); Serial.println(addr1);

// tempo=EEPROM.read(addr1); addr1++;

Serial.print(tempo,DEC);Serial.println(""); tempo=tempo*256+EEPROM.read(addr1); addr1++; Serial.print(tempo,DEC);Serial.println(""); while(EEPROM.read(addr1)>0)

{

notes=EEPROM.read(addr1); addr1++; beats=EEPROM.read(addr1); addr1++;

Serial.print(notes);Serial.print(" "); Serial.print(beats,DEC);Serial.println(" ");

 

if (notes == ' ')

tone(speakerPin,0, beats*tempo*1000L); // пауза else

playNote(notes, beats*tempo);

// пауза между нотами delay(tempo / 2);

}

Serial.println("end");

}

}

Рекомендуем:

int

Побитовый свдиг влево (<<), побитовый сдвиг вправо (>>)

Константы

digitalRead()

setBitOrder()

transfer()

setDataMode()

SPI на Arduino Due

setClockDivider()

SoftwareSerial

analogReference(type)

Wire

SPI

attachInterrupt()

pinMode()

EEPROM

 

 

Вверх

 

Основные версии плат Arduino

Due — плата на базе 32-битного ARM микропроцессора Cortex-M3 ARM SAM3U4E;

Leonardo — плата на микроконтроллере ATmega32U4;

Uno — самая популярная версия базовой платформы Arduino;

Duemilanove — плата на микроконтроллере ATmega168 или ATmega328;

Diecimila — версия базовой платформы Arduino USB;

Nano — компактная платформа, используемая как макет. Nano подключается к компьютеру при помощи кабеля USB Mini-B;

Mega ADK — версия платы Mega 2560 с поддержкой интерфейса USB-host для связи с телефонами на Android и другими устройствами с интерфейсом USB;

Mega2560 — плата на базе микроконтроллера ATmega2560 с использованием чипа ATMega8U2 для последовательного соединения по USB-порту;

Mega — версия серии Mega на базе микроконтроллера ATmega1280;

Arduino BT — платформа с модулем Bluetooth для беспроводной связи и программирования;

LilyPad — платформа, разработанная для переноски, может зашиваться в ткань;

Fio — платформа разработана для беспроводных применений. Fio содержит разъем для радио XBee, разъем для батареи LiPo и встроенную схему подзарядки;

Mini — самая маленькая платформа Arduino;

Pro — платформа, разработанная для опытных пользователей, может являться частью большего проекта;

Pro Mini — как и платформа Pro, разработана для опытных пользователей, которым требуется низкая цена, меньшие размеры и дополнительная функциональность.