Читаем данные (ноты) с EEPROM 24c04 и проигрываем музыку на Arduino

Решил объединить две записи:
– Как подключить 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 и более…

Добавить комментарий