Решил объединить две записи:
– Как подключить AT24C04 I2C EEPROM к Arduino? (“микроник.рус/7622/”)
– Играем музыку на Arduino через пьезодинамик (“микроник.рус/7563/”)
И получил возможность читать данные с внешней EEPROM и анализировать их на микроконтроллере, в частности на Ардуино. Можно увеличить память микроконтроллера или вовсе читать часть программы с внешней EEPROM…
Вот черновой код – рабочий:
Ноты хранятся на AT24C04 – Ардуино их читает и воспроизводит музыку. AT24C04 (или любая другая) – будут выступать в виде пластинок с музыкой!!! Вытаскиваем пластинку – музыки нет, вставляем разные AT24C04 со своей музыкой…
Схема соединения:
и пьезодинамик:
Вот моё устройство:
Вот пример кода, более подробно разберём его ниже
#include <Wire.h>
#define EEPROM_I2C_ADDRESS_0 0x50
#define EEPROM_I2C_ADDRESS_1 0x51
int EEPROM_I2C_ADDRESS = NULL;
int i=0;
int p0=0;
int p1=0;
int p2=0;
int p3=0;
int p4=0;
int p5=0;
int p6=0;
int p7=0;
int p8=0;
int p9=0;
int d=0;
// измените это значение, чтобы сделать песню медленнее или быстрее
int tempo=144;
// замените этот pin на тот, который вы хотите использовать
int buzzer = 11;
// ноты мелодии с указанием длительности.
// 4 означает четвертную ноту, 8 — восемнадцатую, 16 — шестнадцатую и так далее
// !!отрицательные числа используются для обозначения нот с точками,
// так, -4 означает четвертную ноту с точкой, то есть четверть плюс восемнадцатая!!
int melody[] = {0,4,0,8,0,8,0,4,0,8,0,8};
// sizeof gives the number of bytes, each int value is composed of two bytes (16 bits)
// there are two values per note (pitch and duration), so for each note there are four bytes
int notes=sizeof(melody)/sizeof(melody[0])/2;
// this calculates the duration of a whole note in ms (60s/tempo)*4 beats
int wholenote = (60000 * 4) / tempo;
int divider = 0, noteDuration = 0;
void setup()
{
Wire.begin();
Serial.begin(9600);
pinMode(13, OUTPUT);
for(i=0;i<10;i++)
{
if(i<256)
{
EEPROM_I2C_ADDRESS = 0x50;
writeAT24(i, 65+i);
}
else
{
EEPROM_I2C_ADDRESS = 0x51;
writeAT24(i-256, 0);
}
}
delay(1000);
Serial.println("Data from EEPROM");
Serial.println("-----------------");
for(i=0;i<10;i++)
{
if(i<256)
{
EEPROM_I2C_ADDRESS = 0x50;
Serial.println((char)readAT24(i));
Serial.println(i);
p0=(char)readAT24(0);
p1=(char)readAT24(1);
p2=(char)readAT24(2);
p3=(char)readAT24(3);
p4=(char)readAT24(4);
p5=(char)readAT24(5);
p6=(char)readAT24(6);
p7=(char)readAT24(7);
p8=(char)readAT24(8);
p9=(char)readAT24(9);
}
else
{
EEPROM_I2C_ADDRESS = 0x51;
Serial.println((char)readAT24(i-256));
}
}
delay(1000);
Serial.println("Cicl end");
kkk();
}
void loop()
{
}
// Function to write to EEPROOM
void writeAT24(byte dataAddress, byte dataVal)
{
Wire.beginTransmission(EEPROM_I2C_ADDRESS);
Wire.write(dataAddress);
Wire.write(dataVal);
Wire.endTransmission();
delay(5);
}
// Function to read from EEPROM
byte readAT24(byte dataAddress)
{
byte readData = NULL;
Wire.beginTransmission(EEPROM_I2C_ADDRESS);
Wire.write(dataAddress);
Wire.endTransmission();
delay(5);
Wire.requestFrom(EEPROM_I2C_ADDRESS, 1);
//delay(1);
if(Wire.available())
{
readData = Wire.read();
}
return readData;
}
void kkk()
{
Serial.println("M");
melody[0]=p0;
melody[1]=4;
melody[2]=p2;
melody[3]=8;
melody[4]=p4;
melody[5]=8;
melody[6]=p6;
melody[7]=4;
melody[8]=p8;
melody[9]=8;
melody[10]=494;
melody[11]=8;
Serial.println(melody[8]);
// iterate over the notes of the melody.
// Remember, the array is twice the number of notes (notes + durations)
for (int thisNote = 0; thisNote < notes * 2; thisNote = thisNote + 2) {
// calculates the duration of each note
divider = melody[thisNote + 1];
if (divider > 0) {
// regular note, just proceed
noteDuration = (wholenote) / divider;
} else if (divider < 0) {
// dotted notes are represented with negative durations!!
noteDuration = (wholenote) / abs(divider);
noteDuration *= 1.5; // increases the duration in half for dotted notes
}
// we only play the note for 90% of the duration, leaving 10% as a pause
tone(buzzer, melody[thisNote], noteDuration*0.9);
// Wait for the specief duration before playing the next note.
delay(noteDuration);
// stop the waveform generation before the next note.
noTone(buzzer);
}
}
—————————————————
Один из главных фрагментов – это массив:
———————————————————-
Здесь нужно указать размер массива – заполнить его хоть 0 – сколько 0 такая и длина песни – если укажите 10 штук, то больше 5 нот и не пропишите, так как после ноты нужно указать её длительность.
int melody[] = {0,4,0,8,0,8,0,4,0,8,0,8};
———————————————
С помощью вот этого фрагмента мы можем записать во внешнюю EEPROM ноты и другую информацию:
———————————————————–
or(i=0;i<10;i++)
{
if(i<256)
{
EEPROM_I2C_ADDRESS = 0x50;
writeAT24(i, 65+i);
}
else
{
EEPROM_I2C_ADDRESS = 0x51;
writeAT24(i-256, 0);
}
}
Здесь цикл for с i<10, то есть записываем 10 символов (если хотите больше увеличиваете цифру, но не забываем максимальное число, согласно таблице ниже - это 127 или 7F в шестнадцатеричной системе hex):
- мы можем записывать во внешнюю память символы согласно таблицы:

Код writeAT24(i, 65+i) – начинаем запись с 0 ячейки, но значения с 65 символа, то есть будут записаны 65, 66,.. символы, согласно таблице это A,B,..
Можно также отредактировать память внешней EEPROM с помощью программатора ch341 и программ для Linux (“микроник.рус/7575/” и “микроник.рус/7613/”), для Windows XP проги будут следующими (“микроник.рус/6770/”).
————————————————–
Следующий фрагмент – Чтение из внешней EEPROM:
for(i=0;i<10;i++)
{
if(i<256)
{
EEPROM_I2C_ADDRESS = 0x50;
Serial.println((char)readAT24(i));
Serial.println(i);
p0=(char)readAT24(0);
p1=(char)readAT24(1);
p2=(char)readAT24(2);
p3=(char)readAT24(3);
p4=(char)readAT24(4);
p5=(char)readAT24(5);
p6=(char)readAT24(6);
p7=(char)readAT24(7);
p8=(char)readAT24(8);
p9=(char)readAT24(9);
}
else
{
EEPROM_I2C_ADDRESS = 0x51;
Serial.println((char)readAT24(i-256));
}
}
Здесь всё просто – читаем 10 символов, можно упростить код вот так:
for(i=0;i<11;i++)
{
if(i<256)
{
EEPROM_I2C_ADDRESS = 0x50;
Serial.println((char)readAT24(i));
Serial.println(i);
melody[i]=(char)readAT24(i);
}
else
{
EEPROM_I2C_ADDRESS = 0x51;
Serial.println((char)readAT24(i-256));
}
}
То есть указали:
melody[i]=(char)readAT24(i);
То есть заполняем массив соответствующим символом из внешней EEPROM.
melody[0]=(char)readAT24(0); melody[1]=(char)readAT24(1); ...
==============================================================================
Примечание:
=====================================
Вот мой код для теста – он записывает во внешнюю память EEPROM 24c04 следующий массив:
65,4,67,8,69,8,71,4,73,8,75,8
А далее читает эти цифры и играем по ним мелодию
#include <Wire.h>
#define EEPROM_I2C_ADDRESS_0 0x50
#define EEPROM_I2C_ADDRESS_1 0x51
int EEPROM_I2C_ADDRESS = NULL;
int i=0;
// измените это значение, чтобы сделать песню медленнее или быстрее
int tempo=144;
// замените этот pin на тот, который вы хотите использовать
int buzzer = 11;
// ноты мелодии с указанием длительности.
// 4 означает четвертную ноту, 8 — восемнадцатую, 16 — шестнадцатую и так далее
// !!отрицательные числа используются для обозначения нот с точками,
// так, -4 означает четвертную ноту с точкой, то есть четверть плюс восемнадцатая!!
int melody[] = {0,4,0,8,0,8,0,4,0,8,0,8};
// sizeof gives the number of bytes, each int value is composed of two bytes (16 bits)
// there are two values per note (pitch and duration), so for each note there are four bytes
int notes=sizeof(melody)/sizeof(melody[0])/2;
// this calculates the duration of a whole note in ms (60s/tempo)*4 beats
int wholenote = (60000 * 4) / tempo;
int divider = 0, noteDuration = 0;
void setup()
{
Wire.begin();
Serial.begin(9600);
pinMode(13, OUTPUT);
EEPROM_I2C_ADDRESS = 0x50;
writeAT24(0, 65);
writeAT24(1, 4);
writeAT24(2, 67);
writeAT24(3, 8);
writeAT24(4, 69);
writeAT24(5, 8);
writeAT24(6, 71);
writeAT24(7, 4);
writeAT24(8, 73);
writeAT24(9, 8);
writeAT24(10, 75);
writeAT24(11, 8);
delay(1000);
Serial.println("Data from EEPROM");
Serial.println("-----------------");
for(i=0;i<11;i++)
{
if(i<256)
{
EEPROM_I2C_ADDRESS = 0x50;
Serial.println((char)readAT24(i));
Serial.println(i);
melody[i]=(char)readAT24(i);
}
else
{
EEPROM_I2C_ADDRESS = 0x51;
Serial.println((char)readAT24(i-256));
}
}
delay(1000);
Serial.println("Cicl end");
kkk();
}
void loop()
{
}
// Function to write to EEPROOM
void writeAT24(byte dataAddress, byte dataVal)
{
Wire.beginTransmission(EEPROM_I2C_ADDRESS);
Wire.write(dataAddress);
Wire.write(dataVal);
Wire.endTransmission();
delay(5);
}
// Function to read from EEPROM
byte readAT24(byte dataAddress)
{
byte readData = NULL;
Wire.beginTransmission(EEPROM_I2C_ADDRESS);
Wire.write(dataAddress);
Wire.endTransmission();
delay(5);
Wire.requestFrom(EEPROM_I2C_ADDRESS, 1);
//delay(1);
if(Wire.available())
{
readData = Wire.read();
}
return readData;
}
void kkk()
{
Serial.println("M");
Serial.println(melody[0]);
Serial.println(melody[1]);
Serial.println(melody[2]);
Serial.println(melody[3]);
Serial.println(melody[4]);
Serial.println(melody[5]);
Serial.println(melody[6]);
Serial.println(melody[7]);
Serial.println(melody[8]);
Serial.println(melody[9]);
Serial.println(melody[10]);
Serial.println(melody[11]);
// iterate over the notes of the melody.
// Remember, the array is twice the number of notes (notes + durations)
for (int thisNote = 0; thisNote < notes * 2; thisNote = thisNote + 2) {
// calculates the duration of each note
divider = melody[thisNote + 1];
if (divider > 0) {
// regular note, just proceed
noteDuration = (wholenote) / divider;
} else if (divider < 0) {
// dotted notes are represented with negative durations!!
noteDuration = (wholenote) / abs(divider);
noteDuration *= 1.5; // increases the duration in half for dotted notes
}
// we only play the note for 90% of the duration, leaving 10% as a pause
tone(buzzer, melody[thisNote], noteDuration*0.9);
// Wait for the specief duration before playing the next note.
delay(noteDuration);
// stop the waveform generation before the next note.
noTone(buzzer);
}
}
——————————————-мелодию из Тетриса——————————-
Вышеуказанный код использует ноты частотой до 127 Гц (максимальное число, согласно таблице ASCII ниже – это 127 или 7F), но что если мы хотим увеличить частоту – например, чтобы играть мелодию из Тетриса, нужна частота 629 – тогда можно использовать суммирование нескольких чисел в цикле, а также два массива:
#include <SPIFlash.h>
#include <Wire.h>
#define EEPROM_I2C_ADDRESS_0 0x50
#define EEPROM_I2C_ADDRESS_1 0x51
int EEPROM_I2C_ADDRESS = NULL;
int i=0;
int p=0;
// измените это значение, чтобы сделать песню медленнее или быстрее
int tempo=144;
// замените этот pin на тот, который вы хотите использовать
int buzzer = 11;
// ноты мелодии с указанием длительности.
// 4 означает четвертную ноту, 8 — восемнадцатую, 16 — шестнадцатую и так далее
// !!отрицательные числа используются для обозначения нот с точками,
// так, -4 означает четвертную ноту с точкой, то есть четверть плюс восемнадцатая!!
int melody[] = {0,0,0,0,0,0,0,0,0,0,0,0};
int pmelody[] = {0,0,0,0,0,0,0,0,0,0,0,0};
// sizeof gives the number of bytes, each int value is composed of two bytes (16 bits)
// there are two values per note (pitch and duration), so for each note there are four bytes
int notes=sizeof(melody)/sizeof(melody[0])/2;
// this calculates the duration of a whole note in ms (60s/tempo)*4 beats
int wholenote = (60000 * 4) / tempo;
int divider = 0, noteDuration = 0;
void setup()
{
Wire.begin();
Serial.begin(9600);
pinMode(13, OUTPUT);
EEPROM_I2C_ADDRESS = 0x50;
writeAT24(0, 100);
writeAT24(1, 100);
writeAT24(2, 100);
writeAT24(3, 120);
writeAT24(4, 120);
writeAT24(5, 119);
writeAT24(6, 0);
writeAT24(7, 0);
writeAT24(8, 0);
writeAT24(9, 0);
writeAT24(10, 0);
writeAT24(11, 4);
writeAT24(12, 100);
writeAT24(13, 100);
writeAT24(14, 100);
writeAT24(15, 100);
writeAT24(16, 0);
writeAT24(17, 94);
writeAT24(18, 0);
writeAT24(19, 0);
writeAT24(20, 0);
writeAT24(21, 0);
writeAT24(22, 0);
writeAT24(23, 8);
writeAT24(24, 100);
writeAT24(25, 100);
writeAT24(26, 100);
writeAT24(27, 100);
writeAT24(28, 100);
writeAT24(29, 23);
writeAT24(30, 0);
writeAT24(31, 0);
writeAT24(32, 0);
writeAT24(33, 0);
writeAT24(34, 0);
writeAT24(35, 8);
writeAT24(36, 100);
writeAT24(37, 100);
writeAT24(38, 100);
writeAT24(39, 100);
writeAT24(40, 100);
writeAT24(41, 87);
writeAT24(42, 0);
writeAT24(43, 0);
writeAT24(44, 0);
writeAT24(45, 0);
writeAT24(46, 0);
writeAT24(47, 4);
writeAT24(48, 100);
writeAT24(49, 100);
writeAT24(50, 100);
writeAT24(51, 100);
writeAT24(52, 100);
writeAT24(53, 23);
writeAT24(54, 0);
writeAT24(55, 0);
writeAT24(56, 0);
writeAT24(57, 0);
writeAT24(58, 0);
writeAT24(59, 8);
writeAT24(60, 100);
writeAT24(61, 100);
writeAT24(62, 100);
writeAT24(63, 100);
writeAT24(64, 0);
writeAT24(65, 94);
writeAT24(66, 0);
writeAT24(67, 0);
writeAT24(68, 0);
writeAT24(69, 0);
writeAT24(70, 0);
writeAT24(71, 8);
delay(1000);
Serial.println("Data from EEPROM");
Serial.println("-----------------");
for(i=5;i<72;i=i+6,p++)
{
if(i<256)
{
EEPROM_I2C_ADDRESS = 0x50;
Serial.println((char)readAT24(i));
Serial.println(i);
pmelody[p]=(char)readAT24(i)+(char)readAT24(i-1)+(char)readAT24(i-2)+(char)readAT24(i-3)+(char)readAT24(i-4)+(char)readAT24(i-5);
melody[p]=pmelody[p];
}
else
{
EEPROM_I2C_ADDRESS = 0x51;
Serial.println((char)readAT24(i-256));
}
}
delay(1000);
Serial.println("Cicl end");
kkk();
}
void loop()
{
}
// Function to write to EEPROOM
void writeAT24(byte dataAddress, byte dataVal)
{
Wire.beginTransmission(EEPROM_I2C_ADDRESS);
Wire.write(dataAddress);
Wire.write(dataVal);
Wire.endTransmission();
delay(5);
}
// Function to read from EEPROM
byte readAT24(byte dataAddress)
{
byte readData = NULL;
Wire.beginTransmission(EEPROM_I2C_ADDRESS);
Wire.write(dataAddress);
Wire.endTransmission();
delay(5);
Wire.requestFrom(EEPROM_I2C_ADDRESS, 1);
//delay(1);
if(Wire.available())
{
readData = Wire.read();
}
return readData;
}
void kkk()
{
Serial.println("M");
Serial.println(melody[0]);
Serial.println(melody[1]);
Serial.println(melody[2]);
Serial.println(melody[3]);
Serial.println(melody[4]);
Serial.println(melody[5]);
Serial.println(melody[6]);
Serial.println(melody[7]);
Serial.println(melody[8]);
Serial.println(melody[9]);
Serial.println(melody[10]);
Serial.println(melody[11]);
melody[11]=8;
// iterate over the notes of the melody.
// Remember, the array is twice the number of notes (notes + durations)
for (int thisNote = 0; thisNote < notes * 2; thisNote = thisNote + 2) {
// calculates the duration of each note
divider = melody[thisNote + 1];
if (divider > 0) {
// regular note, just proceed
noteDuration = (wholenote) / divider;
} else if (divider < 0) {
// dotted notes are represented with negative durations!!
noteDuration = (wholenote) / abs(divider);
noteDuration *= 1.5; // increases the duration in half for dotted notes
}
// we only play the note for 90% of the duration, leaving 10% as a pause
tone(buzzer, melody[thisNote], noteDuration*0.9);
// Wait for the specief duration before playing the next note.
delay(noteDuration);
// stop the waveform generation before the next note.
noTone(buzzer);
}
}
В итоге у нас прозвучит 6 нот – по которым можно с легкостью узнать мелодию из Тетрис!!!
Аналогичным способом можно увеличить частоту и до 1000 и более…





