Я использую автономный Atmega328P с двумя пьезоэлементами для создания музыки.
Я определил некоторые константы с частотами музыкальных нот.
Затем я определил структуру, которая содержит примечание для первого и второго пьезо и длину примечания.
Затем я сделал больше массивов этих структур для описания каждой песни.
Проблема в том, что таким образом у меня быстро кончается память.
Я попытался сохранить массивы структур в PROGMEM, чтобы избежать этой проблемы.
Я попытался использовать небольшую библиотеку с именем PROGMEM_readAnything, функции memcpy_P () или pgm_read_word () и pgm_read_byte (), но во всех случаях у меня возникает одна и та же проблема.
Когда я перебираю массив NOTES, он пропускает некоторые элементы, а читает и воспроизводит остальные правильно.
Он всегда пропускает одни и те же элементы, а не только случайные.
Я даже пытался заменить микроконтроллер, думая, что некоторые части чипа могли быть чем-то повреждены, но при загрузке того же эскиза я получил те же результаты, поэтому микроконтроллер, вероятно, не поврежден.
Вот код:
#include <Tone.h>
#include <avr/pgmspace.h>
//Define the notes frq
#define G2 98
#define Gs2 104
#define Ab2 104
#define A2 110
#define As2 116
//... and so on with many other music notes ...
#define Fs7 2960
#define Gb7 2960
#define G7 3136
//Rest
#define R 0
typedef struct {
int n1;
int n2;
byte units;
} NOTES;
Tone buzzer1;
Tone buzzer2;
int myTempo = 100;
//Walkyrie
const NOTES walkyrie[] PROGMEM = {
{Fs3, Fs4, 2},
{B3, B4,3},
{Fs3, Fs4, 1},
{B3, B4, 2},
{D4, D5, 6},
{B3, B4, 6},
{D4, D5, 3},
{B3, B4, 1},
{D4, D5, 2},
{Fs4, Fs5, 6},
{D4, D5, 6},
{Fs4, Fs5, 3},
{D4, D5, 1},
{Fs4, Fs5, 2},
{A4, A5, 6},
{A3, A4, 6},
{D4, D5, 3},
{A3, A4, 1},
{D4, D5, 2},
{Fs4, Fs5, 6},
{R, 0, 4},
{A3, A4, 2},
{D4, D5, 3},
{A3, A4, 1},
{D4, D5, 2},
{Fs4, Fs5, 6},
{D4, D5, 6},
{Fs4, Fs5, 3},
{D4, D5, 1},
{Fs4, Fs5, 2},
{A4, A5, 6},
{Fs4, Fs5, 6},
{A4, A5, 3},
{Fs4, Fs5, 1},
{A4, A5, 2},
{Cs5, Cs6, 6},
{Cs4, Cs5, 6},
{Fs4, Fs5, 3},
{Cs4, Cs5, 1},
{Fs4, Fs5, 2},
{As4, As5, 6}};
void playSong()
{
//We store the frq of the second pizo in this variable
int secondFrq = 0;
Serial.println(sizeof(walkyrie)/sizeof(walkyrie[0]));
//Walk through the array of music
for(int i = 0; i < sizeof(walkyrie)/sizeof(walkyrie[0]); i++)
{
int n1;
int n2;
byte units;
// Only play if it is not a rest
if(walkyrie[i].n1 > 0)
{n1 = pgm_read_word(&(walkyrie[i].n1));
n2 = pgm_read_word(&(walkyrie[i].n2));
units = pgm_read_byte(&(walkyrie[i].units));
Serial.print("Row ");
Serial.print(i);
Serial.print(": Frq1: ");
Serial.print(n1);
Serial.print(" Frq2: ");
Serial.print(n2);
Serial.print(" Units: ");
Serial.println(units);
//Play the note of the first piezo
buzzer1.play(n1, (units*myTempo));
//If the frq of the second piezo is 0, we play the same note as the first, else the note set for the second one
if(n2 == 0)
{
secondFrq = n1;
}else{
secondFrq = n2;
}
buzzer2.play(secondFrq, (units*myTempo));
}
//Then we wait for the note to end plus a little, between two notes
delay((units*myTempo) + 10);
}
}void setup() {
Serial.begin(9600);
buzzer1.begin(11);
buzzer2.begin(12);
}
void loop()
{
playSong();
}
Я добавил несколько строк, чтобы увидеть в последовательном мониторе, что происходит.
Это читает правильную длину …
Вывод последовательного монитора следующий:
41 (correct length)
Row 1: Frq1: 247 Frq2: 499 Units: 3 (row 0 - the first note is already missing)
Row 2: Frq1: 185 Frq2: 370 Units: 1
Row 3: Frq1: 247 Frq2: 499 Units: 2 (row 4 missing)
Row 5: Frq1: 247 Frq2: 499 Units: 6 (row 6-7 missing)
Row 8: Frq1: 294 Frq2: 587 Units: 2
Row 9: Frq1: 370 Frq2: 740 Units: 6
Row 10: Frq1: 294 Frq2: 587 Units: 6
Row 11: Frq1: 370 Frq2: 740 Units: 3
Row 12: Frq1: 294 Frq2: 587 Units: 1
Row 13: Frq1: 370 Frq2: 740 Units: 2
Row 14: Frq1: 440 Frq2: 880 Units: 6
Row 15: Frq1: 220 Frq2: 440 Units: 6 (row 16-17 missing)
Row 18: Frq1: 294 Frq2: 587 Units: 2
Row 19: Frq1: 370 Frq2: 740 Units: 6
Row 20: Frq1: 0 Frq2: 0 Units: 4
Row 21: Frq1: 220 Frq2: 440 Units: 2
Row 22: Frq1: 294 Frq2: 587 Units: 3
Row 23: Frq1: 220 Frq2: 440 Units: 1
Row 24: Frq1: 294 Frq2: 587 Units: 2
Row 25: Frq1: 370 Frq2: 740 Units: 6
Row 26: Frq1: 294 Frq2: 587 Units: 6
Row 27: Frq1: 370 Frq2: 740 Units: 3
Row 28: Frq1: 294 Frq2: 587 Units: 1
Row 29: Frq1: 370 Frq2: 740 Units: 2
Row 30: Frq1: 440 Frq2: 880 Units: 6
Row 31: Frq1: 370 Frq2: 740 Units: 6
Row 32: Frq1: 440 Frq2: 880 Units: 3
Row 33: Frq1: 370 Frq2: 740 Units: 1
Row 34: Frq1: 440 Frq2: 880 Units: 2
Row 35: Frq1: 554 Frq2: 1109 Units: 6
Row 36: Frq1: 277 Frq2: 554 Units: 6
Row 37: Frq1: 370 Frq2: 740 Units: 3
Row 38: Frq1: 277 Frq2: 554 Units: 1
Row 39: Frq1: 370 Frq2: 740 Units: 2
Row 40: Frq1: 466 Frq2: 932 Units: 6
У кого-нибудь есть идеи, почему это происходит?
Или у кого-нибудь есть лучший, более эффективный способ решения этой проблемы?
Заранее большое спасибо за любую помощь.
В этой строке вы проверяете данные, но вы еще не сделали pgm_read_word () для получить данные из флэш-памяти:
if(walkyrie[i].n1 > 0)
Если случайно вы получаете ненулевое значение, тогда вы правильно читаете значения из flash, но в противном случае пропускаете эту строку.
Дополнительные доказательства:
Row 20: Frq1: 0 Frq2: 0 Units: 4
Вот, n1 равен нулю, но этот тест должен был пропустить строку.
Кроме того, логика для «отдыха» немного не в порядке. Прямо сейчас вы не читаете единицы на время отдыха, поэтому он использует предыдущее значение (из проигрываемой ноты).
Я думаю, что сначала я получу все три значения, а затем проверим их.
Я также закодировал бы частоты в байт и использовал бы справочную таблицу для преобразования «номера ключа» в частоту (например, номера клавиш MIDI). Таким образом, ваш массив структур будет немного меньше. Возможно, включите также атрибут __packed__ (что угодно), чтобы избежать заполнения между записями — если экономия места на флэш-памяти имеет значение (тогда вы можете получить больше песен!)
Звучит смешно! Удачи!
Других решений пока нет …